Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / video / fbdev / via / via_i2c.c
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/spinlock.h>
11 #include <linux/module.h>
12 #include <linux/via-core.h>
13 #include <linux/via_i2c.h>
14
15 /*
16  * There can only be one set of these, so there's no point in having
17  * them be dynamically allocated...
18  */
19 #define VIAFB_NUM_I2C           5
20 static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C];
21 static struct viafb_dev *i2c_vdev;  /* Passed in from core */
22
23 static void via_i2c_setscl(void *data, int state)
24 {
25         u8 val;
26         struct via_port_cfg *adap_data = data;
27         unsigned long flags;
28
29         spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
30         val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
31         if (state)
32                 val |= 0x20;
33         else
34                 val &= ~0x20;
35         switch (adap_data->type) {
36         case VIA_PORT_I2C:
37                 val |= 0x01;
38                 break;
39         case VIA_PORT_GPIO:
40                 val |= 0x82;
41                 break;
42         default:
43                 printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
44         }
45         via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
46         spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
47 }
48
49 static int via_i2c_getscl(void *data)
50 {
51         struct via_port_cfg *adap_data = data;
52         unsigned long flags;
53         int ret = 0;
54
55         spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
56         if (adap_data->type == VIA_PORT_GPIO)
57                 via_write_reg_mask(adap_data->io_port, adap_data->ioport_index,
58                         0, 0x80);
59         if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08)
60                 ret = 1;
61         spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
62         return ret;
63 }
64
65 static int via_i2c_getsda(void *data)
66 {
67         struct via_port_cfg *adap_data = data;
68         unsigned long flags;
69         int ret = 0;
70
71         spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
72         if (adap_data->type == VIA_PORT_GPIO)
73                 via_write_reg_mask(adap_data->io_port, adap_data->ioport_index,
74                         0, 0x40);
75         if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04)
76                 ret = 1;
77         spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
78         return ret;
79 }
80
81 static void via_i2c_setsda(void *data, int state)
82 {
83         u8 val;
84         struct via_port_cfg *adap_data = data;
85         unsigned long flags;
86
87         spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
88         val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
89         if (state)
90                 val |= 0x10;
91         else
92                 val &= ~0x10;
93         switch (adap_data->type) {
94         case VIA_PORT_I2C:
95                 val |= 0x01;
96                 break;
97         case VIA_PORT_GPIO:
98                 val |= 0x42;
99                 break;
100         default:
101                 printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
102         }
103         via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
104         spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
105 }
106
107 int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata)
108 {
109         int ret;
110         u8 mm1[] = {0x00};
111         struct i2c_msg msgs[2];
112
113         if (!via_i2c_par[adap].is_active)
114                 return -ENODEV;
115         *pdata = 0;
116         msgs[0].flags = 0;
117         msgs[1].flags = I2C_M_RD;
118         msgs[0].addr = msgs[1].addr = slave_addr / 2;
119         mm1[0] = index;
120         msgs[0].len = 1; msgs[1].len = 1;
121         msgs[0].buf = mm1; msgs[1].buf = pdata;
122         ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
123         if (ret == 2)
124                 ret = 0;
125         else if (ret >= 0)
126                 ret = -EIO;
127
128         return ret;
129 }
130
131 int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data)
132 {
133         int ret;
134         u8 msg[2] = { index, data };
135         struct i2c_msg msgs;
136
137         if (!via_i2c_par[adap].is_active)
138                 return -ENODEV;
139         msgs.flags = 0;
140         msgs.addr = slave_addr / 2;
141         msgs.len = 2;
142         msgs.buf = msg;
143         ret = i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1);
144         if (ret == 1)
145                 ret = 0;
146         else if (ret >= 0)
147                 ret = -EIO;
148
149         return ret;
150 }
151
152 int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len)
153 {
154         int ret;
155         u8 mm1[] = {0x00};
156         struct i2c_msg msgs[2];
157
158         if (!via_i2c_par[adap].is_active)
159                 return -ENODEV;
160         msgs[0].flags = 0;
161         msgs[1].flags = I2C_M_RD;
162         msgs[0].addr = msgs[1].addr = slave_addr / 2;
163         mm1[0] = index;
164         msgs[0].len = 1; msgs[1].len = buff_len;
165         msgs[0].buf = mm1; msgs[1].buf = buff;
166         ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
167         if (ret == 2)
168                 ret = 0;
169         else if (ret >= 0)
170                 ret = -EIO;
171
172         return ret;
173 }
174
175 /*
176  * Allow other viafb subdevices to look up a specific adapter
177  * by port name.
178  */
179 struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which)
180 {
181         struct via_i2c_stuff *stuff = &via_i2c_par[which];
182
183         return &stuff->adapter;
184 }
185 EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter);
186
187
188 static int create_i2c_bus(struct i2c_adapter *adapter,
189                           struct i2c_algo_bit_data *algo,
190                           struct via_port_cfg *adap_cfg,
191                           struct pci_dev *pdev)
192 {
193         algo->setsda = via_i2c_setsda;
194         algo->setscl = via_i2c_setscl;
195         algo->getsda = via_i2c_getsda;
196         algo->getscl = via_i2c_getscl;
197         algo->udelay = 10;
198         algo->timeout = 2;
199         algo->data = adap_cfg;
200
201         sprintf(adapter->name, "viafb i2c io_port idx 0x%02x",
202                 adap_cfg->ioport_index);
203         adapter->owner = THIS_MODULE;
204         adapter->class = I2C_CLASS_DDC;
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
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
249 static int 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         return 0;
263 }
264
265 static struct platform_driver via_i2c_driver = {
266         .driver = {
267                 .name = "viafb-i2c",
268         },
269         .probe = viafb_i2c_probe,
270         .remove = viafb_i2c_remove,
271 };
272
273 int viafb_i2c_init(void)
274 {
275         return platform_driver_register(&via_i2c_driver);
276 }
277
278 void viafb_i2c_exit(void)
279 {
280         platform_driver_unregister(&via_i2c_driver);
281 }