1/*
2    i2c-i810.c - Part of lm_sensors, Linux kernel modules for hardware
3              monitoring
4    Copyright (c) 1998, 1999, 2000  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
9    Based on code written by Ralph Metzler <rjkm@thp.uni-koeln.de> and
10    Simon Vogl
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 2 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*/
26/*
27   This interfaces to the I810/I815 to provide access to
28   the DDC Bus and the I2C Bus.
29
30   SUPPORTED DEVICES	PCI ID
31   i810AA		7121
32   i810AB		7123
33   i810E		7125
34   i815			1132
35   i845G		2562
36*/
37
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/init.h>
41#include <linux/pci.h>
42#include <linux/i2c.h>
43#include <linux/i2c-algo-bit.h>
44#include <asm/io.h>
45
46/* GPIO register locations */
47#define I810_IOCONTROL_OFFSET	0x5000
48#define I810_HVSYNC		0x00	/* not used */
49#define I810_GPIOA		0x10
50#define I810_GPIOB		0x14
51
52/* bit locations in the registers */
53#define SCL_DIR_MASK		0x0001
54#define SCL_DIR			0x0002
55#define SCL_VAL_MASK		0x0004
56#define SCL_VAL_OUT		0x0008
57#define SCL_VAL_IN		0x0010
58#define SDA_DIR_MASK		0x0100
59#define SDA_DIR			0x0200
60#define SDA_VAL_MASK		0x0400
61#define SDA_VAL_OUT		0x0800
62#define SDA_VAL_IN		0x1000
63
64/* initialization states */
65#define INIT1			0x1
66#define INIT2			0x2
67#define INIT3			0x4
68
69/* delays */
70#define CYCLE_DELAY		10
71#define TIMEOUT			(HZ / 2)
72
73static void __iomem *ioaddr;
74
75/* The i810 GPIO registers have individual masks for each bit
76   so we never have to read before writing. Nice. */
77
78static void bit_i810i2c_setscl(void *data, int val)
79{
80	writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK,
81	     ioaddr + I810_GPIOB);
82	readl(ioaddr + I810_GPIOB);	/* flush posted write */
83}
84
85static void bit_i810i2c_setsda(void *data, int val)
86{
87 	writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK,
88	     ioaddr + I810_GPIOB);
89	readl(ioaddr + I810_GPIOB);	/* flush posted write */
90}
91
92/* The GPIO pins are open drain, so the pins could always remain outputs.
93   However, some chip versions don't latch the inputs unless they
94   are set as inputs.
95   We rely on the i2c-algo-bit routines to set the pins high before
96   reading the input from other chips. Following guidance in the 815
97   prog. ref. guide, we do a "dummy write" of 0 to the register before
98   reading which forces the input value to be latched. We presume this
99   applies to the 810 as well; shouldn't hurt anyway. This is necessary to get
100   i2c_algo_bit bit_test=1 to pass. */
101
102static int bit_i810i2c_getscl(void *data)
103{
104	writel(SCL_DIR_MASK, ioaddr + I810_GPIOB);
105	writel(0, ioaddr + I810_GPIOB);
106	return (0 != (readl(ioaddr + I810_GPIOB) & SCL_VAL_IN));
107}
108
109static int bit_i810i2c_getsda(void *data)
110{
111	writel(SDA_DIR_MASK, ioaddr + I810_GPIOB);
112	writel(0, ioaddr + I810_GPIOB);
113	return (0 != (readl(ioaddr + I810_GPIOB) & SDA_VAL_IN));
114}
115
116static void bit_i810ddc_setscl(void *data, int val)
117{
118	writel((val ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK,
119	     ioaddr + I810_GPIOA);
120	readl(ioaddr + I810_GPIOA);	/* flush posted write */
121}
122
123static void bit_i810ddc_setsda(void *data, int val)
124{
125 	writel((val ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK,
126	     ioaddr + I810_GPIOA);
127	readl(ioaddr + I810_GPIOA);	/* flush posted write */
128}
129
130static int bit_i810ddc_getscl(void *data)
131{
132	writel(SCL_DIR_MASK, ioaddr + I810_GPIOA);
133	writel(0, ioaddr + I810_GPIOA);
134	return (0 != (readl(ioaddr + I810_GPIOA) & SCL_VAL_IN));
135}
136
137static int bit_i810ddc_getsda(void *data)
138{
139	writel(SDA_DIR_MASK, ioaddr + I810_GPIOA);
140	writel(0, ioaddr + I810_GPIOA);
141	return (0 != (readl(ioaddr + I810_GPIOA) & SDA_VAL_IN));
142}
143
144static int config_i810(struct pci_dev *dev)
145{
146	unsigned long cadr;
147
148	/* map I810 memory */
149	cadr = dev->resource[1].start;
150	cadr += I810_IOCONTROL_OFFSET;
151	cadr &= PCI_BASE_ADDRESS_MEM_MASK;
152	ioaddr = ioremap_nocache(cadr, 0x1000);
153	if (ioaddr) {
154		bit_i810i2c_setscl(NULL, 1);
155		bit_i810i2c_setsda(NULL, 1);
156		bit_i810ddc_setscl(NULL, 1);
157		bit_i810ddc_setsda(NULL, 1);
158		return 0;
159	}
160	return -ENODEV;
161}
162
163static struct i2c_algo_bit_data i810_i2c_bit_data = {
164	.setsda		= bit_i810i2c_setsda,
165	.setscl		= bit_i810i2c_setscl,
166	.getsda		= bit_i810i2c_getsda,
167	.getscl		= bit_i810i2c_getscl,
168	.udelay		= CYCLE_DELAY,
169	.timeout	= TIMEOUT,
170};
171
172static struct i2c_adapter i810_i2c_adapter = {
173	.owner		= THIS_MODULE,
174	.id		= I2C_HW_B_I810,
175	.name		= "I810/I815 I2C Adapter",
176	.algo_data	= &i810_i2c_bit_data,
177};
178
179static struct i2c_algo_bit_data i810_ddc_bit_data = {
180	.setsda		= bit_i810ddc_setsda,
181	.setscl		= bit_i810ddc_setscl,
182	.getsda		= bit_i810ddc_getsda,
183	.getscl		= bit_i810ddc_getscl,
184	.udelay		= CYCLE_DELAY,
185	.timeout	= TIMEOUT,
186};
187
188static struct i2c_adapter i810_ddc_adapter = {
189	.owner		= THIS_MODULE,
190	.id		= I2C_HW_B_I810,
191	.name		= "I810/I815 DDC Adapter",
192	.algo_data	= &i810_ddc_bit_data,
193};
194
195static struct pci_device_id i810_ids[] __devinitdata = {
196	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1) },
197	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3) },
198	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG) },
199	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC) },
200	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_IG) },
201	{ 0, },
202};
203
204MODULE_DEVICE_TABLE (pci, i810_ids);
205
206static int __devinit i810_probe(struct pci_dev *dev, const struct pci_device_id *id)
207{
208	int retval;
209
210	retval = config_i810(dev);
211	if (retval)
212		return retval;
213	dev_info(&dev->dev, "i810/i815 i2c device found.\n");
214
215	/* set up the sysfs linkage to our parent device */
216	i810_i2c_adapter.dev.parent = &dev->dev;
217	i810_ddc_adapter.dev.parent = &dev->dev;
218
219	retval = i2c_bit_add_bus(&i810_i2c_adapter);
220	if (retval)
221		return retval;
222	retval = i2c_bit_add_bus(&i810_ddc_adapter);
223	if (retval)
224		i2c_del_adapter(&i810_i2c_adapter);
225	return retval;
226}
227
228static void __devexit i810_remove(struct pci_dev *dev)
229{
230	i2c_del_adapter(&i810_ddc_adapter);
231	i2c_del_adapter(&i810_i2c_adapter);
232	iounmap(ioaddr);
233}
234
235static struct pci_driver i810_driver = {
236	.name		= "i810_smbus",
237	.id_table	= i810_ids,
238	.probe		= i810_probe,
239	.remove		= __devexit_p(i810_remove),
240};
241
242static int __init i2c_i810_init(void)
243{
244	return pci_register_driver(&i810_driver);
245}
246
247static void __exit i2c_i810_exit(void)
248{
249	pci_unregister_driver(&i810_driver);
250}
251
252MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
253		"Philip Edelbrock <phil@netroedge.com>, "
254		"Ralph Metzler <rjkm@thp.uni-koeln.de>, "
255		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
256MODULE_DESCRIPTION("I810/I815 I2C/DDC driver");
257MODULE_LICENSE("GPL");
258
259module_init(i2c_i810_init);
260module_exit(i2c_i810_exit);
261