i2c-voodoo3.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. voodoo3.c - Part of lm_sensors, Linux kernel modules for hardware
  3. monitoring
  4. Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>,
  5. Philip Edelbrock <phil@netroedge.com>,
  6. Ralph Metzler <rjkm@thp.uni-koeln.de>, and
  7. Mark D. Studebaker <mdsxyz123@yahoo.com>
  8. Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
  9. Simon Vogl
  10. This program is free software; you can redistribute it and/or modify
  11. it under the terms of the GNU General Public License as published by
  12. the Free Software Foundation; either version 2 of the License, or
  13. (at your option) any later version.
  14. This program is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program; if not, write to the Free Software
  20. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22. /* This interfaces to the I2C bus of the Voodoo3 to gain access to
  23. the BT869 and possibly other I2C devices. */
  24. #include <linux/kernel.h>
  25. #include <linux/module.h>
  26. #include <linux/init.h>
  27. #include <linux/pci.h>
  28. #include <linux/i2c.h>
  29. #include <linux/i2c-algo-bit.h>
  30. #include <asm/io.h>
  31. /* the only registers we use */
  32. #define REG 0x78
  33. #define REG2 0x70
  34. /* bit locations in the register */
  35. #define DDC_ENAB 0x00040000
  36. #define DDC_SCL_OUT 0x00080000
  37. #define DDC_SDA_OUT 0x00100000
  38. #define DDC_SCL_IN 0x00200000
  39. #define DDC_SDA_IN 0x00400000
  40. #define I2C_ENAB 0x00800000
  41. #define I2C_SCL_OUT 0x01000000
  42. #define I2C_SDA_OUT 0x02000000
  43. #define I2C_SCL_IN 0x04000000
  44. #define I2C_SDA_IN 0x08000000
  45. /* initialization states */
  46. #define INIT2 0x2
  47. #define INIT3 0x4
  48. /* delays */
  49. #define CYCLE_DELAY 10
  50. #define TIMEOUT (HZ / 2)
  51. static void __iomem *ioaddr;
  52. /* The voo GPIO registers don't have individual masks for each bit
  53. so we always have to read before writing. */
  54. static void bit_vooi2c_setscl(void *data, int val)
  55. {
  56. unsigned int r;
  57. r = readl(ioaddr + REG);
  58. if (val)
  59. r |= I2C_SCL_OUT;
  60. else
  61. r &= ~I2C_SCL_OUT;
  62. writel(r, ioaddr + REG);
  63. readl(ioaddr + REG); /* flush posted write */
  64. }
  65. static void bit_vooi2c_setsda(void *data, int val)
  66. {
  67. unsigned int r;
  68. r = readl(ioaddr + REG);
  69. if (val)
  70. r |= I2C_SDA_OUT;
  71. else
  72. r &= ~I2C_SDA_OUT;
  73. writel(r, ioaddr + REG);
  74. readl(ioaddr + REG); /* flush posted write */
  75. }
  76. /* The GPIO pins are open drain, so the pins always remain outputs.
  77. We rely on the i2c-algo-bit routines to set the pins high before
  78. reading the input from other chips. */
  79. static int bit_vooi2c_getscl(void *data)
  80. {
  81. return (0 != (readl(ioaddr + REG) & I2C_SCL_IN));
  82. }
  83. static int bit_vooi2c_getsda(void *data)
  84. {
  85. return (0 != (readl(ioaddr + REG) & I2C_SDA_IN));
  86. }
  87. static void bit_vooddc_setscl(void *data, int val)
  88. {
  89. unsigned int r;
  90. r = readl(ioaddr + REG);
  91. if (val)
  92. r |= DDC_SCL_OUT;
  93. else
  94. r &= ~DDC_SCL_OUT;
  95. writel(r, ioaddr + REG);
  96. readl(ioaddr + REG); /* flush posted write */
  97. }
  98. static void bit_vooddc_setsda(void *data, int val)
  99. {
  100. unsigned int r;
  101. r = readl(ioaddr + REG);
  102. if (val)
  103. r |= DDC_SDA_OUT;
  104. else
  105. r &= ~DDC_SDA_OUT;
  106. writel(r, ioaddr + REG);
  107. readl(ioaddr + REG); /* flush posted write */
  108. }
  109. static int bit_vooddc_getscl(void *data)
  110. {
  111. return (0 != (readl(ioaddr + REG) & DDC_SCL_IN));
  112. }
  113. static int bit_vooddc_getsda(void *data)
  114. {
  115. return (0 != (readl(ioaddr + REG) & DDC_SDA_IN));
  116. }
  117. static int config_v3(struct pci_dev *dev)
  118. {
  119. unsigned long cadr;
  120. /* map Voodoo3 memory */
  121. cadr = dev->resource[0].start;
  122. cadr &= PCI_BASE_ADDRESS_MEM_MASK;
  123. ioaddr = ioremap_nocache(cadr, 0x1000);
  124. if (ioaddr) {
  125. writel(0x8160, ioaddr + REG2);
  126. writel(0xcffc0020, ioaddr + REG);
  127. dev_info(&dev->dev, "Using Banshee/Voodoo3 I2C device at %p\n", ioaddr);
  128. return 0;
  129. }
  130. return -ENODEV;
  131. }
  132. static struct i2c_algo_bit_data voo_i2c_bit_data = {
  133. .setsda = bit_vooi2c_setsda,
  134. .setscl = bit_vooi2c_setscl,
  135. .getsda = bit_vooi2c_getsda,
  136. .getscl = bit_vooi2c_getscl,
  137. .udelay = CYCLE_DELAY,
  138. .mdelay = CYCLE_DELAY,
  139. .timeout = TIMEOUT
  140. };
  141. static struct i2c_adapter voodoo3_i2c_adapter = {
  142. .owner = THIS_MODULE,
  143. .class = I2C_CLASS_TV_ANALOG,
  144. .name = "I2C Voodoo3/Banshee adapter",
  145. .algo_data = &voo_i2c_bit_data,
  146. };
  147. static struct i2c_algo_bit_data voo_ddc_bit_data = {
  148. .setsda = bit_vooddc_setsda,
  149. .setscl = bit_vooddc_setscl,
  150. .getsda = bit_vooddc_getsda,
  151. .getscl = bit_vooddc_getscl,
  152. .udelay = CYCLE_DELAY,
  153. .mdelay = CYCLE_DELAY,
  154. .timeout = TIMEOUT
  155. };
  156. static struct i2c_adapter voodoo3_ddc_adapter = {
  157. .owner = THIS_MODULE,
  158. .class = I2C_CLASS_DDC,
  159. .name = "DDC Voodoo3/Banshee adapter",
  160. .algo_data = &voo_ddc_bit_data,
  161. };
  162. static struct pci_device_id voodoo3_ids[] __devinitdata = {
  163. { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3) },
  164. { PCI_DEVICE(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE) },
  165. { 0, }
  166. };
  167. MODULE_DEVICE_TABLE (pci, voodoo3_ids);
  168. static int __devinit voodoo3_probe(struct pci_dev *dev, const struct pci_device_id *id)
  169. {
  170. int retval;
  171. retval = config_v3(dev);
  172. if (retval)
  173. return retval;
  174. /* set up the sysfs linkage to our parent device */
  175. voodoo3_i2c_adapter.dev.parent = &dev->dev;
  176. voodoo3_ddc_adapter.dev.parent = &dev->dev;
  177. retval = i2c_bit_add_bus(&voodoo3_i2c_adapter);
  178. if (retval)
  179. return retval;
  180. retval = i2c_bit_add_bus(&voodoo3_ddc_adapter);
  181. if (retval)
  182. i2c_bit_del_bus(&voodoo3_i2c_adapter);
  183. return retval;
  184. }
  185. static void __devexit voodoo3_remove(struct pci_dev *dev)
  186. {
  187. i2c_bit_del_bus(&voodoo3_i2c_adapter);
  188. i2c_bit_del_bus(&voodoo3_ddc_adapter);
  189. iounmap(ioaddr);
  190. }
  191. static struct pci_driver voodoo3_driver = {
  192. .name = "voodoo3_smbus",
  193. .id_table = voodoo3_ids,
  194. .probe = voodoo3_probe,
  195. .remove = __devexit_p(voodoo3_remove),
  196. };
  197. static int __init i2c_voodoo3_init(void)
  198. {
  199. return pci_register_driver(&voodoo3_driver);
  200. }
  201. static void __exit i2c_voodoo3_exit(void)
  202. {
  203. pci_unregister_driver(&voodoo3_driver);
  204. }
  205. MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
  206. "Philip Edelbrock <phil@netroedge.com>, "
  207. "Ralph Metzler <rjkm@thp.uni-koeln.de>, "
  208. "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
  209. MODULE_DESCRIPTION("Voodoo3 I2C/SMBus driver");
  210. MODULE_LICENSE("GPL");
  211. module_init(i2c_voodoo3_init);
  212. module_exit(i2c_voodoo3_exit);