Merge branch 'master' into next
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / i2c / busses / i2c-parport.c
CommitLineData
1da177e4
LT
1/* ------------------------------------------------------------------------ *
2 * i2c-parport.c I2C bus over parallel port *
3 * ------------------------------------------------------------------------ *
56acc7a3 4 Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org>
1da177e4
LT
5
6 Based on older i2c-philips-par.c driver
7 Copyright (C) 1995-2000 Simon G. Vogl
8 With some changes from:
9 Frodo Looijaard <frodol@dds.nl>
96de0e25 10 Kyösti Mälkki <kmalkki@cc.hut.fi>
1da177e4
LT
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
1da177e4
LT
27#include <linux/kernel.h>
28#include <linux/module.h>
29#include <linux/init.h>
6d376fcc 30#include <linux/delay.h>
1da177e4
LT
31#include <linux/parport.h>
32#include <linux/i2c.h>
33#include <linux/i2c-algo-bit.h>
35859254 34#include <linux/i2c-smbus.h>
5a0e3ad6 35#include <linux/slab.h>
56acc7a3
JD
36#include <linux/list.h>
37#include <linux/mutex.h>
1da177e4
LT
38#include "i2c-parport.h"
39
40/* ----- Device list ------------------------------------------------------ */
41
42struct i2c_par {
43 struct pardevice *pdev;
44 struct i2c_adapter adapter;
45 struct i2c_algo_bit_data algo_data;
35859254
JD
46 struct i2c_smbus_alert_setup alert_data;
47 struct i2c_client *ara;
56acc7a3 48 struct list_head node;
1da177e4
LT
49};
50
56acc7a3
JD
51static LIST_HEAD(adapter_list);
52static DEFINE_MUTEX(adapter_list_lock);
1da177e4
LT
53
54/* ----- Low-level parallel port access ----------------------------------- */
55
56static void port_write_data(struct parport *p, unsigned char d)
57{
58 parport_write_data(p, d);
59}
60
61static void port_write_control(struct parport *p, unsigned char d)
62{
63 parport_write_control(p, d);
64}
65
66static unsigned char port_read_data(struct parport *p)
67{
68 return parport_read_data(p);
69}
70
71static unsigned char port_read_status(struct parport *p)
72{
73 return parport_read_status(p);
74}
75
76static unsigned char port_read_control(struct parport *p)
77{
78 return parport_read_control(p);
79}
80
81static void (*port_write[])(struct parport *, unsigned char) = {
82 port_write_data,
83 NULL,
84 port_write_control,
85};
86
87static unsigned char (*port_read[])(struct parport *) = {
88 port_read_data,
89 port_read_status,
90 port_read_control,
91};
92
93/* ----- Unified line operation functions --------------------------------- */
94
95static inline void line_set(struct parport *data, int state,
96 const struct lineop *op)
97{
98 u8 oldval = port_read[op->port](data);
99
100 /* Touch only the bit(s) needed */
101 if ((op->inverted && !state) || (!op->inverted && state))
102 port_write[op->port](data, oldval | op->val);
103 else
104 port_write[op->port](data, oldval & ~op->val);
105}
106
107static inline int line_get(struct parport *data,
108 const struct lineop *op)
109{
110 u8 oldval = port_read[op->port](data);
111
112 return ((op->inverted && (oldval & op->val) != op->val)
113 || (!op->inverted && (oldval & op->val) == op->val));
114}
115
116/* ----- I2C algorithm call-back functions and structures ----------------- */
117
118static void parport_setscl(void *data, int state)
119{
120 line_set((struct parport *) data, state, &adapter_parm[type].setscl);
121}
122
123static void parport_setsda(void *data, int state)
124{
125 line_set((struct parport *) data, state, &adapter_parm[type].setsda);
126}
127
128static int parport_getscl(void *data)
129{
130 return line_get((struct parport *) data, &adapter_parm[type].getscl);
131}
132
133static int parport_getsda(void *data)
134{
135 return line_get((struct parport *) data, &adapter_parm[type].getsda);
136}
137
138/* Encapsulate the functions above in the correct structure.
139 Note that this is only a template, from which the real structures are
140 copied. The attaching code will set getscl to NULL for adapters that
614e24be 141 cannot read SCL back, and will also make the data field point to
1da177e4 142 the parallel port structure. */
bfdcad90 143static const struct i2c_algo_bit_data parport_algo_data = {
1da177e4
LT
144 .setsda = parport_setsda,
145 .setscl = parport_setscl,
146 .getsda = parport_getsda,
147 .getscl = parport_getscl,
3af07bd2 148 .udelay = 10, /* ~50 kbps */
1da177e4
LT
149 .timeout = HZ,
150};
151
152/* ----- I2c and parallel port call-back functions and structures --------- */
153
35859254
JD
154void i2c_parport_irq(void *data)
155{
156 struct i2c_par *adapter = data;
157 struct i2c_client *ara = adapter->ara;
158
159 if (ara) {
160 dev_dbg(&ara->dev, "SMBus alert received\n");
161 i2c_handle_smbus_alert(ara);
162 } else
163 dev_dbg(&adapter->adapter.dev,
164 "SMBus alert received but no ARA client!\n");
165}
166
1da177e4
LT
167static void i2c_parport_attach (struct parport *port)
168{
169 struct i2c_par *adapter;
170
5263ebb5 171 adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
1da177e4 172 if (adapter == NULL) {
5263ebb5 173 printk(KERN_ERR "i2c-parport: Failed to kzalloc\n");
1da177e4
LT
174 return;
175 }
1da177e4
LT
176
177 pr_debug("i2c-parport: attaching to %s\n", port->name);
35859254 178 parport_disable_irq(port);
1da177e4 179 adapter->pdev = parport_register_device(port, "i2c-parport",
35859254 180 NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
1da177e4
LT
181 if (!adapter->pdev) {
182 printk(KERN_ERR "i2c-parport: Unable to register with parport\n");
183 goto ERROR0;
184 }
185
186 /* Fill the rest of the structure */
cacf2269
JD
187 adapter->adapter.owner = THIS_MODULE;
188 adapter->adapter.class = I2C_CLASS_HWMON;
cacf2269
JD
189 strlcpy(adapter->adapter.name, "Parallel port adapter",
190 sizeof(adapter->adapter.name));
1da177e4 191 adapter->algo_data = parport_algo_data;
3af07bd2
JD
192 /* Slow down if we can't sense SCL */
193 if (!adapter_parm[type].getscl.val) {
1da177e4 194 adapter->algo_data.getscl = NULL;
3af07bd2
JD
195 adapter->algo_data.udelay = 50; /* ~10 kbps */
196 }
1da177e4
LT
197 adapter->algo_data.data = port;
198 adapter->adapter.algo_data = &adapter->algo_data;
da675296 199 adapter->adapter.dev.parent = port->physport->dev;
1da177e4
LT
200
201 if (parport_claim_or_block(adapter->pdev) < 0) {
202 printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");
203 goto ERROR1;
204 }
205
206 /* Reset hardware to a sane state (SCL and SDA high) */
207 parport_setsda(port, 1);
208 parport_setscl(port, 1);
209 /* Other init if needed (power on...) */
6d376fcc 210 if (adapter_parm[type].init.val) {
1da177e4 211 line_set(port, 1, &adapter_parm[type].init);
6d376fcc
JD
212 /* Give powered devices some time to settle */
213 msleep(100);
214 }
1da177e4 215
1da177e4
LT
216 if (i2c_bit_add_bus(&adapter->adapter) < 0) {
217 printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
218 goto ERROR1;
219 }
220
35859254
JD
221 /* Setup SMBus alert if supported */
222 if (adapter_parm[type].smbus_alert) {
223 adapter->alert_data.alert_edge_triggered = 1;
224 adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,
225 &adapter->alert_data);
226 if (adapter->ara)
227 parport_enable_irq(port);
228 else
229 printk(KERN_WARNING "i2c-parport: Failed to register "
230 "ARA client\n");
231 }
232
1da177e4 233 /* Add the new adapter to the list */
56acc7a3
JD
234 mutex_lock(&adapter_list_lock);
235 list_add_tail(&adapter->node, &adapter_list);
236 mutex_unlock(&adapter_list_lock);
1da177e4
LT
237 return;
238
239ERROR1:
7b964f73 240 parport_release(adapter->pdev);
1da177e4
LT
241 parport_unregister_device(adapter->pdev);
242ERROR0:
243 kfree(adapter);
244}
245
246static void i2c_parport_detach (struct parport *port)
247{
56acc7a3 248 struct i2c_par *adapter, *_n;
1da177e4
LT
249
250 /* Walk the list */
56acc7a3
JD
251 mutex_lock(&adapter_list_lock);
252 list_for_each_entry_safe(adapter, _n, &adapter_list, node) {
1da177e4 253 if (adapter->pdev->port == port) {
35859254
JD
254 if (adapter->ara) {
255 parport_disable_irq(port);
256 i2c_unregister_device(adapter->ara);
257 }
3af07bd2
JD
258 i2c_del_adapter(&adapter->adapter);
259
1da177e4
LT
260 /* Un-init if needed (power off...) */
261 if (adapter_parm[type].init.val)
262 line_set(port, 0, &adapter_parm[type].init);
263
7b964f73 264 parport_release(adapter->pdev);
1da177e4 265 parport_unregister_device(adapter->pdev);
56acc7a3 266 list_del(&adapter->node);
1da177e4 267 kfree(adapter);
1da177e4
LT
268 }
269 }
56acc7a3 270 mutex_unlock(&adapter_list_lock);
1da177e4
LT
271}
272
6c129be8 273static struct parport_driver i2c_parport_driver = {
1da177e4
LT
274 .name = "i2c-parport",
275 .attach = i2c_parport_attach,
276 .detach = i2c_parport_detach,
277};
278
279/* ----- Module loading, unloading and information ------------------------ */
280
281static int __init i2c_parport_init(void)
282{
e97b81dd
MH
283 if (type < 0) {
284 printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");
285 return -ENODEV;
286 }
287
288 if (type >= ARRAY_SIZE(adapter_parm)) {
1da177e4 289 printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
e97b81dd 290 return -ENODEV;
1da177e4 291 }
7e3d7db5 292
6c129be8 293 return parport_register_driver(&i2c_parport_driver);
1da177e4
LT
294}
295
296static void __exit i2c_parport_exit(void)
297{
6c129be8 298 parport_unregister_driver(&i2c_parport_driver);
1da177e4
LT
299}
300
301MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
302MODULE_DESCRIPTION("I2C bus over parallel port");
303MODULE_LICENSE("GPL");
304
305module_init(i2c_parport_init);
306module_exit(i2c_parport_exit);