1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
4 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
5
6 */
7
8 #include <linux/platform_device.h>
9 #include <linux/delay.h>
10 #include <linux/export.h>
11 #include <linux/spinlock.h>
12 #include <linux/module.h>
13 #include <linux/via-core.h>
14 #include <linux/via_i2c.h>
15
16 /*
17 * There can only be one set of these, so there's no point in having
18 * them be dynamically allocated...
19 */
20 #define VIAFB_NUM_I2C 5
21 static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C];
22 static struct viafb_dev *i2c_vdev; /* Passed in from core */
23
via_i2c_setscl(void * data,int state)24 static void via_i2c_setscl(void *data, int state)
25 {
26 u8 val;
27 struct via_port_cfg *adap_data = data;
28 unsigned long flags;
29
30 spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
31 val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
32 if (state)
33 val |= 0x20;
34 else
35 val &= ~0x20;
36 switch (adap_data->type) {
37 case VIA_PORT_I2C:
38 val |= 0x01;
39 break;
40 case VIA_PORT_GPIO:
41 val |= 0x82;
42 break;
43 default:
44 printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
45 }
46 via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
47 spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
48 }
49
via_i2c_getscl(void * data)50 static int via_i2c_getscl(void *data)
51 {
52 struct via_port_cfg *adap_data = data;
53 unsigned long flags;
54 int ret = 0;
55
56 spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
57 if (adap_data->type == VIA_PORT_GPIO)
58 via_write_reg_mask(adap_data->io_port, adap_data->ioport_index,
59 0, 0x80);
60 if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08)
61 ret = 1;
62 spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
63 return ret;
64 }
65
via_i2c_getsda(void * data)66 static int via_i2c_getsda(void *data)
67 {
68 struct via_port_cfg *adap_data = data;
69 unsigned long flags;
70 int ret = 0;
71
72 spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
73 if (adap_data->type == VIA_PORT_GPIO)
74 via_write_reg_mask(adap_data->io_port, adap_data->ioport_index,
75 0, 0x40);
76 if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04)
77 ret = 1;
78 spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
79 return ret;
80 }
81
via_i2c_setsda(void * data,int state)82 static void via_i2c_setsda(void *data, int state)
83 {
84 u8 val;
85 struct via_port_cfg *adap_data = data;
86 unsigned long flags;
87
88 spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
89 val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
90 if (state)
91 val |= 0x10;
92 else
93 val &= ~0x10;
94 switch (adap_data->type) {
95 case VIA_PORT_I2C:
96 val |= 0x01;
97 break;
98 case VIA_PORT_GPIO:
99 val |= 0x42;
100 break;
101 default:
102 printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
103 }
104 via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
105 spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
106 }
107
viafb_i2c_readbyte(u8 adap,u8 target_addr,u8 index,u8 * pdata)108 int viafb_i2c_readbyte(u8 adap, u8 target_addr, u8 index, u8 *pdata)
109 {
110 int ret;
111 u8 mm1[] = {0x00};
112 struct i2c_msg msgs[2];
113
114 if (!via_i2c_par[adap].is_active)
115 return -ENODEV;
116 *pdata = 0;
117 msgs[0].flags = 0;
118 msgs[1].flags = I2C_M_RD;
119 msgs[0].addr = msgs[1].addr = target_addr / 2;
120 mm1[0] = index;
121 msgs[0].len = 1; msgs[1].len = 1;
122 msgs[0].buf = mm1; msgs[1].buf = pdata;
123 ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
124 if (ret == 2)
125 ret = 0;
126 else if (ret >= 0)
127 ret = -EIO;
128
129 return ret;
130 }
131
viafb_i2c_writebyte(u8 adap,u8 target_addr,u8 index,u8 data)132 int viafb_i2c_writebyte(u8 adap, u8 target_addr, u8 index, u8 data)
133 {
134 int ret;
135 u8 msg[2] = { index, data };
136 struct i2c_msg msgs;
137
138 if (!via_i2c_par[adap].is_active)
139 return -ENODEV;
140 msgs.flags = 0;
141 msgs.addr = target_addr / 2;
142 msgs.len = 2;
143 msgs.buf = msg;
144 ret = i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1);
145 if (ret == 1)
146 ret = 0;
147 else if (ret >= 0)
148 ret = -EIO;
149
150 return ret;
151 }
152
viafb_i2c_readbytes(u8 adap,u8 target_addr,u8 index,u8 * buff,int buff_len)153 int viafb_i2c_readbytes(u8 adap, u8 target_addr, u8 index, u8 *buff, int buff_len)
154 {
155 int ret;
156 u8 mm1[] = {0x00};
157 struct i2c_msg msgs[2];
158
159 if (!via_i2c_par[adap].is_active)
160 return -ENODEV;
161 msgs[0].flags = 0;
162 msgs[1].flags = I2C_M_RD;
163 msgs[0].addr = msgs[1].addr = target_addr / 2;
164 mm1[0] = index;
165 msgs[0].len = 1; msgs[1].len = buff_len;
166 msgs[0].buf = mm1; msgs[1].buf = buff;
167 ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
168 if (ret == 2)
169 ret = 0;
170 else if (ret >= 0)
171 ret = -EIO;
172
173 return ret;
174 }
175
176 /*
177 * Allow other viafb subdevices to look up a specific adapter
178 * by port name.
179 */
viafb_find_i2c_adapter(enum viafb_i2c_adap which)180 struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which)
181 {
182 struct via_i2c_stuff *stuff = &via_i2c_par[which];
183
184 return &stuff->adapter;
185 }
186 EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter);
187
188
create_i2c_bus(struct i2c_adapter * adapter,struct i2c_algo_bit_data * algo,struct via_port_cfg * adap_cfg,struct pci_dev * pdev)189 static int create_i2c_bus(struct i2c_adapter *adapter,
190 struct i2c_algo_bit_data *algo,
191 struct via_port_cfg *adap_cfg,
192 struct pci_dev *pdev)
193 {
194 algo->setsda = via_i2c_setsda;
195 algo->setscl = via_i2c_setscl;
196 algo->getsda = via_i2c_getsda;
197 algo->getscl = via_i2c_getscl;
198 algo->udelay = 10;
199 algo->timeout = 2;
200 algo->data = adap_cfg;
201
202 sprintf(adapter->name, "viafb i2c io_port idx 0x%02x",
203 adap_cfg->ioport_index);
204 adapter->owner = THIS_MODULE;
205 adapter->algo_data = algo;
206 if (pdev)
207 adapter->dev.parent = &pdev->dev;
208 else
209 adapter->dev.parent = NULL;
210 /* i2c_set_adapdata(adapter, adap_cfg); */
211
212 /* Raise SCL and SDA */
213 via_i2c_setsda(adap_cfg, 1);
214 via_i2c_setscl(adap_cfg, 1);
215 udelay(20);
216
217 return i2c_bit_add_bus(adapter);
218 }
219
viafb_i2c_probe(struct platform_device * platdev)220 static int viafb_i2c_probe(struct platform_device *platdev)
221 {
222 int i, ret;
223 struct via_port_cfg *configs;
224
225 i2c_vdev = platdev->dev.platform_data;
226 configs = i2c_vdev->port_cfg;
227
228 for (i = 0; i < VIAFB_NUM_PORTS; i++) {
229 struct via_port_cfg *adap_cfg = configs++;
230 struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
231
232 i2c_stuff->is_active = 0;
233 if (adap_cfg->type == 0 || adap_cfg->mode != VIA_MODE_I2C)
234 continue;
235 ret = create_i2c_bus(&i2c_stuff->adapter,
236 &i2c_stuff->algo, adap_cfg,
237 NULL); /* FIXME: PCIDEV */
238 if (ret < 0) {
239 printk(KERN_ERR "viafb: cannot create i2c bus %u:%d\n",
240 i, ret);
241 continue; /* Still try to make the rest */
242 }
243 i2c_stuff->is_active = 1;
244 }
245
246 return 0;
247 }
248
viafb_i2c_remove(struct platform_device * platdev)249 static void viafb_i2c_remove(struct platform_device *platdev)
250 {
251 int i;
252
253 for (i = 0; i < VIAFB_NUM_PORTS; i++) {
254 struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
255 /*
256 * Only remove those entries in the array that we've
257 * actually used (and thus initialized algo_data)
258 */
259 if (i2c_stuff->is_active)
260 i2c_del_adapter(&i2c_stuff->adapter);
261 }
262 }
263
264 static struct platform_driver via_i2c_driver = {
265 .driver = {
266 .name = "viafb-i2c",
267 },
268 .probe = viafb_i2c_probe,
269 .remove = viafb_i2c_remove,
270 };
271
viafb_i2c_init(void)272 int viafb_i2c_init(void)
273 {
274 return platform_driver_register(&via_i2c_driver);
275 }
276
viafb_i2c_exit(void)277 void viafb_i2c_exit(void)
278 {
279 platform_driver_unregister(&via_i2c_driver);
280 }
281