/drivers/i2c/busses/i2c-prosavage.c

https://bitbucket.org/evzijst/gittest · C · 334 lines · 191 code · 48 blank · 95 comment · 19 complexity · 4037c27efcbac0d36f4fc8257f8c8108 MD5 · raw file

  1. /*
  2. * kernel/busses/i2c-prosavage.c
  3. *
  4. * i2c bus driver for S3/VIA 8365/8375 graphics processor.
  5. * Copyright (c) 2003 Henk Vergonet <henk@god.dyndns.org>
  6. * Based on code written by:
  7. * Frodo Looijaard <frodol@dds.nl>,
  8. * Philip Edelbrock <phil@netroedge.com>,
  9. * Ralph Metzler <rjkm@thp.uni-koeln.de>, and
  10. * Mark D. Studebaker <mdsxyz123@yahoo.com>
  11. * Simon Vogl
  12. * and others
  13. *
  14. * Please read the lm_sensors documentation for details on use.
  15. *
  16. * This program is free software; you can redistribute it and/or modify
  17. * it under the terms of the GNU General Public License as published by
  18. * the Free Software Foundation; either version 2 of the License, or
  19. * (at your option) any later version.
  20. *
  21. * This program is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software
  28. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29. *
  30. */
  31. /* 18-05-2003 HVE - created
  32. * 14-06-2003 HVE - adapted for lm_sensors2
  33. * 17-06-2003 HVE - linux 2.5.xx compatible
  34. * 18-06-2003 HVE - codingstyle
  35. * 21-06-2003 HVE - compatibility lm_sensors2 and linux 2.5.xx
  36. * codingstyle, mmio enabled
  37. *
  38. * This driver interfaces to the I2C bus of the VIA north bridge embedded
  39. * ProSavage4/8 devices. Usefull for gaining access to the TV Encoder chips.
  40. *
  41. * Graphics cores:
  42. * S3/VIA KM266/VT8375 aka ProSavage8
  43. * S3/VIA KM133/VT8365 aka Savage4
  44. *
  45. * Two serial busses are implemented:
  46. * SERIAL1 - I2C serial communications interface
  47. * SERIAL2 - DDC2 monitor communications interface
  48. *
  49. * Tested on a FX41 mainboard, see http://www.shuttle.com
  50. *
  51. *
  52. * TODO:
  53. * - integration with prosavage framebuffer device
  54. * (Additional documentation needed :(
  55. */
  56. #include <linux/config.h>
  57. #include <linux/module.h>
  58. #include <linux/init.h>
  59. #include <linux/pci.h>
  60. #include <linux/i2c.h>
  61. #include <linux/i2c-algo-bit.h>
  62. #include <asm/io.h>
  63. /*
  64. * driver configuration
  65. */
  66. #define MAX_BUSSES 2
  67. struct s_i2c_bus {
  68. void __iomem *mmvga;
  69. int i2c_reg;
  70. int adap_ok;
  71. struct i2c_adapter adap;
  72. struct i2c_algo_bit_data algo;
  73. };
  74. struct s_i2c_chip {
  75. void __iomem *mmio;
  76. struct s_i2c_bus i2c_bus[MAX_BUSSES];
  77. };
  78. /*
  79. * i2c configuration
  80. */
  81. #ifndef I2C_HW_B_S3VIA
  82. #define I2C_HW_B_S3VIA 0x18 /* S3VIA ProSavage adapter */
  83. #endif
  84. /* delays */
  85. #define CYCLE_DELAY 10
  86. #define TIMEOUT (HZ / 2)
  87. /*
  88. * S3/VIA 8365/8375 registers
  89. */
  90. #define VGA_CR_IX 0x3d4
  91. #define VGA_CR_DATA 0x3d5
  92. #define CR_SERIAL1 0xa0 /* I2C serial communications interface */
  93. #define MM_SERIAL1 0xff20
  94. #define CR_SERIAL2 0xb1 /* DDC2 monitor communications interface */
  95. /* based on vt8365 documentation */
  96. #define I2C_ENAB 0x10
  97. #define I2C_SCL_OUT 0x01
  98. #define I2C_SDA_OUT 0x02
  99. #define I2C_SCL_IN 0x04
  100. #define I2C_SDA_IN 0x08
  101. #define SET_CR_IX(p, val) writeb((val), (p)->mmvga + VGA_CR_IX)
  102. #define SET_CR_DATA(p, val) writeb((val), (p)->mmvga + VGA_CR_DATA)
  103. #define GET_CR_DATA(p) readb((p)->mmvga + VGA_CR_DATA)
  104. /*
  105. * Serial bus line handling
  106. *
  107. * serial communications register as parameter in private data
  108. *
  109. * TODO: locks with other code sections accessing video registers?
  110. */
  111. static void bit_s3via_setscl(void *bus, int val)
  112. {
  113. struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
  114. unsigned int r;
  115. SET_CR_IX(p, p->i2c_reg);
  116. r = GET_CR_DATA(p);
  117. r |= I2C_ENAB;
  118. if (val) {
  119. r |= I2C_SCL_OUT;
  120. } else {
  121. r &= ~I2C_SCL_OUT;
  122. }
  123. SET_CR_DATA(p, r);
  124. }
  125. static void bit_s3via_setsda(void *bus, int val)
  126. {
  127. struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
  128. unsigned int r;
  129. SET_CR_IX(p, p->i2c_reg);
  130. r = GET_CR_DATA(p);
  131. r |= I2C_ENAB;
  132. if (val) {
  133. r |= I2C_SDA_OUT;
  134. } else {
  135. r &= ~I2C_SDA_OUT;
  136. }
  137. SET_CR_DATA(p, r);
  138. }
  139. static int bit_s3via_getscl(void *bus)
  140. {
  141. struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
  142. SET_CR_IX(p, p->i2c_reg);
  143. return (0 != (GET_CR_DATA(p) & I2C_SCL_IN));
  144. }
  145. static int bit_s3via_getsda(void *bus)
  146. {
  147. struct s_i2c_bus *p = (struct s_i2c_bus *)bus;
  148. SET_CR_IX(p, p->i2c_reg);
  149. return (0 != (GET_CR_DATA(p) & I2C_SDA_IN));
  150. }
  151. /*
  152. * adapter initialisation
  153. */
  154. static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iomem *mmvga, u32 i2c_reg)
  155. {
  156. int ret;
  157. p->adap.owner = THIS_MODULE;
  158. p->adap.id = I2C_HW_B_S3VIA;
  159. p->adap.algo_data = &p->algo;
  160. p->adap.dev.parent = &dev->dev;
  161. p->algo.setsda = bit_s3via_setsda;
  162. p->algo.setscl = bit_s3via_setscl;
  163. p->algo.getsda = bit_s3via_getsda;
  164. p->algo.getscl = bit_s3via_getscl;
  165. p->algo.udelay = CYCLE_DELAY;
  166. p->algo.mdelay = CYCLE_DELAY;
  167. p->algo.timeout = TIMEOUT;
  168. p->algo.data = p;
  169. p->mmvga = mmvga;
  170. p->i2c_reg = i2c_reg;
  171. ret = i2c_bit_add_bus(&p->adap);
  172. if (ret) {
  173. return ret;
  174. }
  175. p->adap_ok = 1;
  176. return 0;
  177. }
  178. /*
  179. * Cleanup stuff
  180. */
  181. static void prosavage_remove(struct pci_dev *dev)
  182. {
  183. struct s_i2c_chip *chip;
  184. int i, ret;
  185. chip = (struct s_i2c_chip *)pci_get_drvdata(dev);
  186. if (!chip) {
  187. return;
  188. }
  189. for (i = MAX_BUSSES - 1; i >= 0; i--) {
  190. if (chip->i2c_bus[i].adap_ok == 0)
  191. continue;
  192. ret = i2c_bit_del_bus(&chip->i2c_bus[i].adap);
  193. if (ret) {
  194. dev_err(&dev->dev, "%s not removed\n",
  195. chip->i2c_bus[i].adap.name);
  196. }
  197. }
  198. if (chip->mmio) {
  199. iounmap(chip->mmio);
  200. }
  201. kfree(chip);
  202. }
  203. /*
  204. * Detect chip and initialize it
  205. */
  206. static int __devinit prosavage_probe(struct pci_dev *dev, const struct pci_device_id *id)
  207. {
  208. int ret;
  209. unsigned long base, len;
  210. struct s_i2c_chip *chip;
  211. struct s_i2c_bus *bus;
  212. pci_set_drvdata(dev, kmalloc(sizeof(struct s_i2c_chip), GFP_KERNEL));
  213. chip = (struct s_i2c_chip *)pci_get_drvdata(dev);
  214. if (chip == NULL) {
  215. return -ENOMEM;
  216. }
  217. memset(chip, 0, sizeof(struct s_i2c_chip));
  218. base = dev->resource[0].start & PCI_BASE_ADDRESS_MEM_MASK;
  219. len = dev->resource[0].end - base + 1;
  220. chip->mmio = ioremap_nocache(base, len);
  221. if (chip->mmio == NULL) {
  222. dev_err(&dev->dev, "ioremap failed\n");
  223. prosavage_remove(dev);
  224. return -ENODEV;
  225. }
  226. /*
  227. * Chip initialisation
  228. */
  229. /* Unlock Extended IO Space ??? */
  230. /*
  231. * i2c bus registration
  232. */
  233. bus = &chip->i2c_bus[0];
  234. snprintf(bus->adap.name, sizeof(bus->adap.name),
  235. "ProSavage I2C bus at %02x:%02x.%x",
  236. dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
  237. ret = i2c_register_bus(dev, bus, chip->mmio + 0x8000, CR_SERIAL1);
  238. if (ret) {
  239. goto err_adap;
  240. }
  241. /*
  242. * ddc bus registration
  243. */
  244. bus = &chip->i2c_bus[1];
  245. snprintf(bus->adap.name, sizeof(bus->adap.name),
  246. "ProSavage DDC bus at %02x:%02x.%x",
  247. dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
  248. ret = i2c_register_bus(dev, bus, chip->mmio + 0x8000, CR_SERIAL2);
  249. if (ret) {
  250. goto err_adap;
  251. }
  252. return 0;
  253. err_adap:
  254. dev_err(&dev->dev, "%s failed\n", bus->adap.name);
  255. prosavage_remove(dev);
  256. return ret;
  257. }
  258. /*
  259. * Data for PCI driver interface
  260. */
  261. static struct pci_device_id prosavage_pci_tbl[] = {
  262. { PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SAVAGE4) },
  263. { PCI_DEVICE(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_PROSAVAGE8) },
  264. { 0, },
  265. };
  266. MODULE_DEVICE_TABLE (pci, prosavage_pci_tbl);
  267. static struct pci_driver prosavage_driver = {
  268. .name = "prosavage_smbus",
  269. .id_table = prosavage_pci_tbl,
  270. .probe = prosavage_probe,
  271. .remove = prosavage_remove,
  272. };
  273. static int __init i2c_prosavage_init(void)
  274. {
  275. return pci_register_driver(&prosavage_driver);
  276. }
  277. static void __exit i2c_prosavage_exit(void)
  278. {
  279. pci_unregister_driver(&prosavage_driver);
  280. }
  281. MODULE_DEVICE_TABLE(pci, prosavage_pci_tbl);
  282. MODULE_AUTHOR("Henk Vergonet");
  283. MODULE_DESCRIPTION("ProSavage VIA 8365/8375 smbus driver");
  284. MODULE_LICENSE("GPL");
  285. module_init (i2c_prosavage_init);
  286. module_exit (i2c_prosavage_exit);