]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - drivers/media/pci/tw68/tw68-i2c.c
[media] tw68: add original tw68 code
[mirror_ubuntu-hirsute-kernel.git] / drivers / media / pci / tw68 / tw68-i2c.c
1 /*
2 * tw68 code to handle the i2c interface.
3 *
4 * Much of this code is derived from the bt87x driver. The original
5 * work was by Gerd Knorr; more recently the code was enhanced by Mauro
6 * Carvalho Chehab. Their work is gratefully acknowledged. Full credit
7 * goes to them - any problems within this code are mine.
8 *
9 * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26 #include <linux/init.h>
27 #include <linux/list.h>
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/slab.h>
31 #include <linux/delay.h>
32
33 #include "tw68.h"
34 #include <media/v4l2-common.h>
35 #include <linux/i2c-algo-bit.h>
36
37 /*----------------------------------------------------------------*/
38
39 static unsigned int i2c_debug;
40 module_param(i2c_debug, int, 0644);
41 MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
42
43 #if 0
44 static unsigned int i2c_scan;
45 module_param(i2c_scan, int, 0444);
46 MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
47 #endif
48
49 #define d1printk if (1 == i2c_debug) printk
50
51 #define I2C_CLOCK 0xa6 /* 99.4 kHz */
52
53 /*----------------------------------------------------------------------*/
54 /* Although the TW68xx i2c controller has a "hardware" mode, where all of
55 * the low-level i2c/smbbus is handled by the chip, it appears that mode
56 * is not suitable for linux i2c handling routines because extended "bursts"
57 * of data (sequences of bytes without intervening START/STOP bits) are
58 * not possible. Instead, we put the chip into "software" mode, and handle
59 * the i2c bus at a low level. To accomplish this, we use the routines
60 * from the i2c modules.
61 *
62 * Because the particular boards which I had for testing did not have any
63 * devices attached to the i2c bus, I have been unable to test these
64 * routines.
65 */
66
67 /*----------------------------------------------------------------------*/
68 /* I2C functions - "bit-banging" adapter (software i2c) */
69
70 /* tw68_bit_setcl
71 * Handles "toggling" the i2c clock bit
72 */
73 static void tw68_bit_setscl(void *data, int state)
74 {
75 struct tw68_dev *dev = data;
76
77 tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSCLK, TW68_SSCLK_B);
78 }
79
80 /* tw68_bit_setsda
81 * Handles "toggling" the i2c data bit
82 */
83 static void tw68_bit_setsda(void *data, int state)
84 {
85 struct tw68_dev *dev = data;
86
87 tw_andorb(TW68_SBUSC, (state ? 1 : 0) << TW68_SSDAT, TW68_SSDAT_B);
88 }
89
90 /* tw68_bit_getscl
91 *
92 * Returns the current state of the clock bit
93 */
94 static int tw68_bit_getscl(void *data)
95 {
96 struct tw68_dev *dev = data;
97
98 return (tw_readb(TW68_SBUSC) & TW68_SSCLK_B) ? 1 : 0;
99 }
100
101 /* tw68_bit_getsda
102 *
103 * Returns the current state of the data bit
104 */
105 static int tw68_bit_getsda(void *data)
106 {
107 struct tw68_dev *dev = data;
108
109 return (tw_readb(TW68_SBUSC) & TW68_SSDAT_B) ? 1 : 0;
110 }
111
112 static struct i2c_algo_bit_data __devinitdata tw68_i2c_algo_bit_template = {
113 .setsda = tw68_bit_setsda,
114 .setscl = tw68_bit_setscl,
115 .getsda = tw68_bit_getsda,
116 .getscl = tw68_bit_getscl,
117 .udelay = 16,
118 .timeout = 200,
119 };
120
121 static struct i2c_client tw68_client_template = {
122 .name = "tw68 internal",
123 };
124
125 /*----------------------------------------------------------------*/
126
127 static int attach_inform(struct i2c_client *client)
128 {
129 /* struct tw68_dev *dev = client->adapter->algo_data; */
130
131 d1printk("%s i2c attach [addr=0x%x,client=%s]\n",
132 client->driver->driver.name, client->addr, client->name);
133
134 switch (client->addr) {
135 /* No info yet on what addresses to expect */
136 }
137
138 return 0;
139 }
140
141 static struct i2c_adapter tw68_adap_sw_template = {
142 .owner = THIS_MODULE,
143 .name = "tw68_sw",
144 .client_register = attach_inform,
145 };
146
147 static int tw68_i2c_eeprom(struct tw68_dev *dev, unsigned char *eedata,
148 int len)
149 {
150 unsigned char buf;
151 int i, err;
152
153 dev->i2c_client.addr = 0xa0 >> 1;
154 buf = 256 - len;
155
156 err = i2c_master_send(&dev->i2c_client, &buf, 1);
157 if (1 != err) {
158 printk(KERN_INFO "%s: Huh, no eeprom present (err = %d)?\n",
159 dev->name, err);
160 return -1;
161 }
162 err = i2c_master_recv(&dev->i2c_client, eedata, len);
163 if (len != err) {
164 printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n",
165 dev->name, err);
166 return -1;
167 }
168
169 for (i = 0; i < len; i++) {
170 if (0 == (i % 16))
171 printk(KERN_INFO "%s: i2c eeprom %02x:",
172 dev->name, i);
173 printk(KERN_INFO " %02x", eedata[i]);
174 if (15 == (i % 16))
175 printk("\n");
176 }
177 return 0;
178 }
179
180 #if 0
181 static char *i2c_devs[128] = {
182 [0xa0 >> 1] = "eeprom",
183 };
184
185 static void do_i2c_scan(char *name, struct i2c_client *c)
186 {
187 unsigned char buf;
188 int i, rc;
189
190 for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) {
191 c->addr = i;
192 rc = i2c_master_recv(c, &buf, 1);
193 if (rc < 0)
194 continue;
195 printk(KERN_INFO "%s: i2c scan: found device "
196 "@ 0x%x [%s]\n", name, i << 1,
197 i2c_devs[i] ? i2c_devs[i] : "???");
198 }
199 }
200 #endif
201
202 int __devinit tw68_i2c_register(struct tw68_dev *dev)
203 {
204 int rc;
205
206 printk(KERN_DEBUG "%s: Registering i2c module\n", __func__);
207 tw_writeb(TW68_I2C_RST, 1); /* reset the i2c module */
208
209 memcpy(&dev->i2c_client, &tw68_client_template,
210 sizeof(tw68_client_template));
211
212 memcpy(&dev->i2c_adap, &tw68_adap_sw_template,
213 sizeof(tw68_adap_sw_template));
214 dev->i2c_adap.algo_data = &dev->i2c_algo;
215 dev->i2c_adap.dev.parent = &dev->pci->dev;
216
217 memcpy(&dev->i2c_algo, &tw68_i2c_algo_bit_template,
218 sizeof(tw68_i2c_algo_bit_template));
219 dev->i2c_algo.data = dev;
220 /* TODO - may want to set better name (see bttv code) */
221
222 i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
223 dev->i2c_client.adapter = &dev->i2c_adap;
224
225 /* Assure chip is in "software" mode */
226 tw_writel(TW68_SBUSC, TW68_SSDAT | TW68_SSCLK);
227 tw68_bit_setscl(dev, 1);
228 tw68_bit_setsda(dev, 1);
229
230 rc = i2c_bit_add_bus(&dev->i2c_adap);
231
232 tw68_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata));
233 #if 0
234 if (i2c_scan)
235 do_i2c_scan(dev->name, &dev->i2c_client);
236 #endif
237
238 return rc;
239 }
240
241 int tw68_i2c_unregister(struct tw68_dev *dev)
242 {
243 i2c_del_adapter(&dev->i2c_adap);
244 return 0;
245 }