xref: /openbmc/linux/drivers/i2c/busses/i2c-parport.c (revision ea1558ce)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /* ------------------------------------------------------------------------ *
31da177e4SLinus Torvalds  * i2c-parport.c I2C bus over parallel port                                 *
41da177e4SLinus Torvalds  * ------------------------------------------------------------------------ *
57c81c60fSJean Delvare    Copyright (C) 2003-2011 Jean Delvare <jdelvare@suse.de>
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds    Based on older i2c-philips-par.c driver
81da177e4SLinus Torvalds    Copyright (C) 1995-2000 Simon G. Vogl
91da177e4SLinus Torvalds    With some changes from:
101da177e4SLinus Torvalds    Frodo Looijaard <frodol@dds.nl>
1196de0e25SJan Engelhardt    Kyösti Mälkki <kmalkki@cc.hut.fi>
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds  * ------------------------------------------------------------------------ */
141da177e4SLinus Torvalds 
1520226118SSudip Mukherjee #define pr_fmt(fmt) "i2c-parport: " fmt
1620226118SSudip Mukherjee 
171da177e4SLinus Torvalds #include <linux/kernel.h>
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds #include <linux/init.h>
206d376fccSJean Delvare #include <linux/delay.h>
211da177e4SLinus Torvalds #include <linux/parport.h>
221da177e4SLinus Torvalds #include <linux/i2c.h>
231da177e4SLinus Torvalds #include <linux/i2c-algo-bit.h>
2435859254SJean Delvare #include <linux/i2c-smbus.h>
255a0e3ad6STejun Heo #include <linux/slab.h>
2656acc7a3SJean Delvare #include <linux/list.h>
2756acc7a3SJean Delvare #include <linux/mutex.h>
289f7a0364SWolfram Sang 
299f7a0364SWolfram Sang #define PORT_DATA	0
309f7a0364SWolfram Sang #define PORT_STAT	1
319f7a0364SWolfram Sang #define PORT_CTRL	2
329f7a0364SWolfram Sang 
339f7a0364SWolfram Sang struct lineop {
349f7a0364SWolfram Sang 	u8 val;
359f7a0364SWolfram Sang 	u8 port;
369f7a0364SWolfram Sang 	u8 inverted;
379f7a0364SWolfram Sang };
389f7a0364SWolfram Sang 
399f7a0364SWolfram Sang struct adapter_parm {
409f7a0364SWolfram Sang 	struct lineop setsda;
419f7a0364SWolfram Sang 	struct lineop setscl;
429f7a0364SWolfram Sang 	struct lineop getsda;
439f7a0364SWolfram Sang 	struct lineop getscl;
449f7a0364SWolfram Sang 	struct lineop init;
459f7a0364SWolfram Sang 	unsigned int smbus_alert:1;
469f7a0364SWolfram Sang };
479f7a0364SWolfram Sang 
489f7a0364SWolfram Sang static const struct adapter_parm adapter_parm[] = {
499f7a0364SWolfram Sang 	/* type 0: Philips adapter */
509f7a0364SWolfram Sang 	{
519f7a0364SWolfram Sang 		.setsda	= { 0x80, PORT_DATA, 1 },
529f7a0364SWolfram Sang 		.setscl	= { 0x08, PORT_CTRL, 0 },
539f7a0364SWolfram Sang 		.getsda	= { 0x80, PORT_STAT, 0 },
549f7a0364SWolfram Sang 		.getscl	= { 0x08, PORT_STAT, 0 },
559f7a0364SWolfram Sang 	},
569f7a0364SWolfram Sang 	/* type 1: home brew teletext adapter */
579f7a0364SWolfram Sang 	{
589f7a0364SWolfram Sang 		.setsda	= { 0x02, PORT_DATA, 0 },
599f7a0364SWolfram Sang 		.setscl	= { 0x01, PORT_DATA, 0 },
609f7a0364SWolfram Sang 		.getsda	= { 0x80, PORT_STAT, 1 },
619f7a0364SWolfram Sang 	},
629f7a0364SWolfram Sang 	/* type 2: Velleman K8000 adapter */
639f7a0364SWolfram Sang 	{
649f7a0364SWolfram Sang 		.setsda	= { 0x02, PORT_CTRL, 1 },
659f7a0364SWolfram Sang 		.setscl	= { 0x08, PORT_CTRL, 1 },
669f7a0364SWolfram Sang 		.getsda	= { 0x10, PORT_STAT, 0 },
679f7a0364SWolfram Sang 	},
689f7a0364SWolfram Sang 	/* type 3: ELV adapter */
699f7a0364SWolfram Sang 	{
709f7a0364SWolfram Sang 		.setsda	= { 0x02, PORT_DATA, 1 },
719f7a0364SWolfram Sang 		.setscl	= { 0x01, PORT_DATA, 1 },
729f7a0364SWolfram Sang 		.getsda	= { 0x40, PORT_STAT, 1 },
739f7a0364SWolfram Sang 		.getscl	= { 0x08, PORT_STAT, 1 },
749f7a0364SWolfram Sang 	},
759f7a0364SWolfram Sang 	/* type 4: ADM1032 evaluation board */
769f7a0364SWolfram Sang 	{
779f7a0364SWolfram Sang 		.setsda	= { 0x02, PORT_DATA, 1 },
789f7a0364SWolfram Sang 		.setscl	= { 0x01, PORT_DATA, 1 },
799f7a0364SWolfram Sang 		.getsda	= { 0x10, PORT_STAT, 1 },
809f7a0364SWolfram Sang 		.init	= { 0xf0, PORT_DATA, 0 },
819f7a0364SWolfram Sang 		.smbus_alert = 1,
829f7a0364SWolfram Sang 	},
839f7a0364SWolfram Sang 	/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
849f7a0364SWolfram Sang 	{
859f7a0364SWolfram Sang 		.setsda	= { 0x02, PORT_DATA, 1 },
869f7a0364SWolfram Sang 		.setscl	= { 0x01, PORT_DATA, 1 },
879f7a0364SWolfram Sang 		.getsda	= { 0x10, PORT_STAT, 1 },
889f7a0364SWolfram Sang 	},
899f7a0364SWolfram Sang 	/* type 6: Barco LPT->DVI (K5800236) adapter */
909f7a0364SWolfram Sang 	{
919f7a0364SWolfram Sang 		.setsda	= { 0x02, PORT_DATA, 1 },
929f7a0364SWolfram Sang 		.setscl	= { 0x01, PORT_DATA, 1 },
939f7a0364SWolfram Sang 		.getsda	= { 0x20, PORT_STAT, 0 },
949f7a0364SWolfram Sang 		.getscl	= { 0x40, PORT_STAT, 0 },
959f7a0364SWolfram Sang 		.init	= { 0xfc, PORT_DATA, 0 },
969f7a0364SWolfram Sang 	},
979f7a0364SWolfram Sang 	/* type 7: One For All JP1 parallel port adapter */
989f7a0364SWolfram Sang 	{
999f7a0364SWolfram Sang 		.setsda	= { 0x01, PORT_DATA, 0 },
1009f7a0364SWolfram Sang 		.setscl	= { 0x02, PORT_DATA, 0 },
1019f7a0364SWolfram Sang 		.getsda	= { 0x80, PORT_STAT, 1 },
1029f7a0364SWolfram Sang 		.init	= { 0x04, PORT_DATA, 1 },
1039f7a0364SWolfram Sang 	},
1049f7a0364SWolfram Sang 	/* type 8: VCT-jig */
1059f7a0364SWolfram Sang 	{
1069f7a0364SWolfram Sang 		.setsda	= { 0x04, PORT_DATA, 1 },
1079f7a0364SWolfram Sang 		.setscl	= { 0x01, PORT_DATA, 1 },
1089f7a0364SWolfram Sang 		.getsda	= { 0x40, PORT_STAT, 0 },
1099f7a0364SWolfram Sang 		.getscl	= { 0x80, PORT_STAT, 1 },
1109f7a0364SWolfram Sang 	},
1119f7a0364SWolfram Sang };
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds /* ----- Device list ------------------------------------------------------ */
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds struct i2c_par {
1161da177e4SLinus Torvalds 	struct pardevice *pdev;
1171da177e4SLinus Torvalds 	struct i2c_adapter adapter;
1181da177e4SLinus Torvalds 	struct i2c_algo_bit_data algo_data;
11935859254SJean Delvare 	struct i2c_smbus_alert_setup alert_data;
12035859254SJean Delvare 	struct i2c_client *ara;
12156acc7a3SJean Delvare 	struct list_head node;
1221da177e4SLinus Torvalds };
1231da177e4SLinus Torvalds 
12456acc7a3SJean Delvare static LIST_HEAD(adapter_list);
12556acc7a3SJean Delvare static DEFINE_MUTEX(adapter_list_lock);
1269f7a0364SWolfram Sang 
12719a4fb21SSudip Mukherjee #define MAX_DEVICE 4
12819a4fb21SSudip Mukherjee static int parport[MAX_DEVICE] = {0, -1, -1, -1};
1299f7a0364SWolfram Sang module_param_array(parport, int, NULL, 0);
1309f7a0364SWolfram Sang MODULE_PARM_DESC(parport,
1319f7a0364SWolfram Sang 		 "List of parallel ports to bind to, by index.\n"
1329f7a0364SWolfram Sang 		 " At most " __stringify(MAX_DEVICE) " devices are supported.\n"
1339f7a0364SWolfram Sang 		 " Default is one device connected to parport0.\n"
1349f7a0364SWolfram Sang );
13519a4fb21SSudip Mukherjee 
1369f7a0364SWolfram Sang static int type = -1;
1379f7a0364SWolfram Sang module_param(type, int, 0);
1389f7a0364SWolfram Sang MODULE_PARM_DESC(type,
1399f7a0364SWolfram Sang 	"Type of adapter:\n"
1409f7a0364SWolfram Sang 	" 0 = Philips adapter\n"
1419f7a0364SWolfram Sang 	" 1 = home brew teletext adapter\n"
1429f7a0364SWolfram Sang 	" 2 = Velleman K8000 adapter\n"
1439f7a0364SWolfram Sang 	" 3 = ELV adapter\n"
1449f7a0364SWolfram Sang 	" 4 = ADM1032 evaluation board\n"
1459f7a0364SWolfram Sang 	" 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n"
1469f7a0364SWolfram Sang 	" 6 = Barco LPT->DVI (K5800236) adapter\n"
1479f7a0364SWolfram Sang 	" 7 = One For All JP1 parallel port adapter\n"
1489f7a0364SWolfram Sang 	" 8 = VCT-jig\n"
1499f7a0364SWolfram Sang );
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds /* ----- Low-level parallel port access ----------------------------------- */
1521da177e4SLinus Torvalds 
port_write_data(struct parport * p,unsigned char d)1531da177e4SLinus Torvalds static void port_write_data(struct parport *p, unsigned char d)
1541da177e4SLinus Torvalds {
1551da177e4SLinus Torvalds 	parport_write_data(p, d);
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
port_write_control(struct parport * p,unsigned char d)1581da177e4SLinus Torvalds static void port_write_control(struct parport *p, unsigned char d)
1591da177e4SLinus Torvalds {
1601da177e4SLinus Torvalds 	parport_write_control(p, d);
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds 
port_read_data(struct parport * p)1631da177e4SLinus Torvalds static unsigned char port_read_data(struct parport *p)
1641da177e4SLinus Torvalds {
1651da177e4SLinus Torvalds 	return parport_read_data(p);
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds 
port_read_status(struct parport * p)1681da177e4SLinus Torvalds static unsigned char port_read_status(struct parport *p)
1691da177e4SLinus Torvalds {
1701da177e4SLinus Torvalds 	return parport_read_status(p);
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds 
port_read_control(struct parport * p)1731da177e4SLinus Torvalds static unsigned char port_read_control(struct parport *p)
1741da177e4SLinus Torvalds {
1751da177e4SLinus Torvalds 	return parport_read_control(p);
1761da177e4SLinus Torvalds }
1771da177e4SLinus Torvalds 
17807da0372SJean Delvare static void (* const port_write[])(struct parport *, unsigned char) = {
1791da177e4SLinus Torvalds 	port_write_data,
1801da177e4SLinus Torvalds 	NULL,
1811da177e4SLinus Torvalds 	port_write_control,
1821da177e4SLinus Torvalds };
1831da177e4SLinus Torvalds 
18407da0372SJean Delvare static unsigned char (* const port_read[])(struct parport *) = {
1851da177e4SLinus Torvalds 	port_read_data,
1861da177e4SLinus Torvalds 	port_read_status,
1871da177e4SLinus Torvalds 	port_read_control,
1881da177e4SLinus Torvalds };
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds /* ----- Unified line operation functions --------------------------------- */
1911da177e4SLinus Torvalds 
line_set(struct parport * data,int state,const struct lineop * op)1921da177e4SLinus Torvalds static inline void line_set(struct parport *data, int state,
1931da177e4SLinus Torvalds 	const struct lineop *op)
1941da177e4SLinus Torvalds {
1951da177e4SLinus Torvalds 	u8 oldval = port_read[op->port](data);
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	/* Touch only the bit(s) needed */
1981da177e4SLinus Torvalds 	if ((op->inverted && !state) || (!op->inverted && state))
1991da177e4SLinus Torvalds 		port_write[op->port](data, oldval | op->val);
2001da177e4SLinus Torvalds 	else
2011da177e4SLinus Torvalds 		port_write[op->port](data, oldval & ~op->val);
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds 
line_get(struct parport * data,const struct lineop * op)2041da177e4SLinus Torvalds static inline int line_get(struct parport *data,
2051da177e4SLinus Torvalds 	const struct lineop *op)
2061da177e4SLinus Torvalds {
2071da177e4SLinus Torvalds 	u8 oldval = port_read[op->port](data);
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	return ((op->inverted && (oldval & op->val) != op->val)
2101da177e4SLinus Torvalds 	    || (!op->inverted && (oldval & op->val) == op->val));
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds /* ----- I2C algorithm call-back functions and structures ----------------- */
2141da177e4SLinus Torvalds 
parport_setscl(void * data,int state)2151da177e4SLinus Torvalds static void parport_setscl(void *data, int state)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds 	line_set((struct parport *) data, state, &adapter_parm[type].setscl);
2181da177e4SLinus Torvalds }
2191da177e4SLinus Torvalds 
parport_setsda(void * data,int state)2201da177e4SLinus Torvalds static void parport_setsda(void *data, int state)
2211da177e4SLinus Torvalds {
2221da177e4SLinus Torvalds 	line_set((struct parport *) data, state, &adapter_parm[type].setsda);
2231da177e4SLinus Torvalds }
2241da177e4SLinus Torvalds 
parport_getscl(void * data)2251da177e4SLinus Torvalds static int parport_getscl(void *data)
2261da177e4SLinus Torvalds {
2271da177e4SLinus Torvalds 	return line_get((struct parport *) data, &adapter_parm[type].getscl);
2281da177e4SLinus Torvalds }
2291da177e4SLinus Torvalds 
parport_getsda(void * data)2301da177e4SLinus Torvalds static int parport_getsda(void *data)
2311da177e4SLinus Torvalds {
2321da177e4SLinus Torvalds 	return line_get((struct parport *) data, &adapter_parm[type].getsda);
2331da177e4SLinus Torvalds }
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds /* Encapsulate the functions above in the correct structure.
2361da177e4SLinus Torvalds    Note that this is only a template, from which the real structures are
2371da177e4SLinus Torvalds    copied. The attaching code will set getscl to NULL for adapters that
238614e24beSTobias Klauser    cannot read SCL back, and will also make the data field point to
2391da177e4SLinus Torvalds    the parallel port structure. */
240bfdcad90SJean Delvare static const struct i2c_algo_bit_data parport_algo_data = {
2411da177e4SLinus Torvalds 	.setsda		= parport_setsda,
2421da177e4SLinus Torvalds 	.setscl		= parport_setscl,
2431da177e4SLinus Torvalds 	.getsda		= parport_getsda,
2441da177e4SLinus Torvalds 	.getscl		= parport_getscl,
2453af07bd2SJean Delvare 	.udelay		= 10, /* ~50 kbps */
2461da177e4SLinus Torvalds 	.timeout	= HZ,
2471da177e4SLinus Torvalds };
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds /* ----- I2c and parallel port call-back functions and structures --------- */
2501da177e4SLinus Torvalds 
i2c_parport_irq(void * data)2517fe442a1SJean Delvare static void i2c_parport_irq(void *data)
25235859254SJean Delvare {
25335859254SJean Delvare 	struct i2c_par *adapter = data;
25435859254SJean Delvare 	struct i2c_client *ara = adapter->ara;
25535859254SJean Delvare 
25635859254SJean Delvare 	if (ara) {
25735859254SJean Delvare 		dev_dbg(&ara->dev, "SMBus alert received\n");
25835859254SJean Delvare 		i2c_handle_smbus_alert(ara);
25935859254SJean Delvare 	} else
26035859254SJean Delvare 		dev_dbg(&adapter->adapter.dev,
26135859254SJean Delvare 			"SMBus alert received but no ARA client!\n");
26235859254SJean Delvare }
26335859254SJean Delvare 
i2c_parport_attach(struct parport * port)2641da177e4SLinus Torvalds static void i2c_parport_attach(struct parport *port)
2651da177e4SLinus Torvalds {
2661da177e4SLinus Torvalds 	struct i2c_par *adapter;
26719a4fb21SSudip Mukherjee 	int i;
26819a4fb21SSudip Mukherjee 	struct pardev_cb i2c_parport_cb;
26919a4fb21SSudip Mukherjee 
2709c5b1daaSAndy Shevchenko 	if (type < 0) {
2719c5b1daaSAndy Shevchenko 		pr_warn("adapter type unspecified\n");
2729c5b1daaSAndy Shevchenko 		return;
2739c5b1daaSAndy Shevchenko 	}
2749c5b1daaSAndy Shevchenko 
2759c5b1daaSAndy Shevchenko 	if (type >= ARRAY_SIZE(adapter_parm)) {
2769c5b1daaSAndy Shevchenko 		pr_warn("invalid type (%d)\n", type);
2779c5b1daaSAndy Shevchenko 		return;
2789c5b1daaSAndy Shevchenko 	}
2799c5b1daaSAndy Shevchenko 
28019a4fb21SSudip Mukherjee 	for (i = 0; i < MAX_DEVICE; i++) {
28119a4fb21SSudip Mukherjee 		if (parport[i] == -1)
28219a4fb21SSudip Mukherjee 			continue;
28319a4fb21SSudip Mukherjee 		if (port->number == parport[i])
28419a4fb21SSudip Mukherjee 			break;
28519a4fb21SSudip Mukherjee 	}
28619a4fb21SSudip Mukherjee 	if (i == MAX_DEVICE) {
28720226118SSudip Mukherjee 		pr_debug("Not using parport%d.\n", port->number);
28819a4fb21SSudip Mukherjee 		return;
28919a4fb21SSudip Mukherjee 	}
2901da177e4SLinus Torvalds 
2915263ebb5SDeepak Saxena 	adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
29220226118SSudip Mukherjee 	if (!adapter)
2931da177e4SLinus Torvalds 		return;
2948891f41aSSudip Mukherjee 	memset(&i2c_parport_cb, 0, sizeof(i2c_parport_cb));
2958891f41aSSudip Mukherjee 	i2c_parport_cb.flags = PARPORT_FLAG_EXCL;
2968891f41aSSudip Mukherjee 	i2c_parport_cb.irq_func = i2c_parport_irq;
2978891f41aSSudip Mukherjee 	i2c_parport_cb.private = adapter;
2981da177e4SLinus Torvalds 
29920226118SSudip Mukherjee 	pr_debug("attaching to %s\n", port->name);
30035859254SJean Delvare 	parport_disable_irq(port);
3018891f41aSSudip Mukherjee 	adapter->pdev = parport_register_dev_model(port, "i2c-parport",
3028891f41aSSudip Mukherjee 						   &i2c_parport_cb, i);
3031da177e4SLinus Torvalds 	if (!adapter->pdev) {
30420226118SSudip Mukherjee 		pr_err("Unable to register with parport\n");
30507da0372SJean Delvare 		goto err_free;
3061da177e4SLinus Torvalds 	}
3071da177e4SLinus Torvalds 
3081da177e4SLinus Torvalds 	/* Fill the rest of the structure */
309cacf2269SJean Delvare 	adapter->adapter.owner = THIS_MODULE;
310cacf2269SJean Delvare 	adapter->adapter.class = I2C_CLASS_HWMON;
311*ea1558ceSWolfram Sang 	strscpy(adapter->adapter.name, "Parallel port adapter",
312cacf2269SJean Delvare 		sizeof(adapter->adapter.name));
3131da177e4SLinus Torvalds 	adapter->algo_data = parport_algo_data;
3143af07bd2SJean Delvare 	/* Slow down if we can't sense SCL */
3153af07bd2SJean Delvare 	if (!adapter_parm[type].getscl.val) {
3161da177e4SLinus Torvalds 		adapter->algo_data.getscl = NULL;
3173af07bd2SJean Delvare 		adapter->algo_data.udelay = 50; /* ~10 kbps */
3183af07bd2SJean Delvare 	}
3191da177e4SLinus Torvalds 	adapter->algo_data.data = port;
3201da177e4SLinus Torvalds 	adapter->adapter.algo_data = &adapter->algo_data;
321da675296SDavid Brownell 	adapter->adapter.dev.parent = port->physport->dev;
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 	if (parport_claim_or_block(adapter->pdev) < 0) {
324c5f3d544SSudip Mukherjee 		dev_err(&adapter->pdev->dev,
325c5f3d544SSudip Mukherjee 			"Could not claim parallel port\n");
32607da0372SJean Delvare 		goto err_unregister;
3271da177e4SLinus Torvalds 	}
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds 	/* Reset hardware to a sane state (SCL and SDA high) */
3301da177e4SLinus Torvalds 	parport_setsda(port, 1);
3311da177e4SLinus Torvalds 	parport_setscl(port, 1);
3321da177e4SLinus Torvalds 	/* Other init if needed (power on...) */
3336d376fccSJean Delvare 	if (adapter_parm[type].init.val) {
3341da177e4SLinus Torvalds 		line_set(port, 1, &adapter_parm[type].init);
3356d376fccSJean Delvare 		/* Give powered devices some time to settle */
3366d376fccSJean Delvare 		msleep(100);
3376d376fccSJean Delvare 	}
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	if (i2c_bit_add_bus(&adapter->adapter) < 0) {
340c5f3d544SSudip Mukherjee 		dev_err(&adapter->pdev->dev, "Unable to register with I2C\n");
34107da0372SJean Delvare 		goto err_unregister;
3421da177e4SLinus Torvalds 	}
3431da177e4SLinus Torvalds 
34435859254SJean Delvare 	/* Setup SMBus alert if supported */
34535859254SJean Delvare 	if (adapter_parm[type].smbus_alert) {
346ed680522SWolfram Sang 		struct i2c_client *ara;
347ed680522SWolfram Sang 
348ed680522SWolfram Sang 		ara = i2c_new_smbus_alert_device(&adapter->adapter,
34935859254SJean Delvare 						 &adapter->alert_data);
350ed680522SWolfram Sang 		if (!IS_ERR(ara)) {
351ed680522SWolfram Sang 			adapter->ara = ara;
35235859254SJean Delvare 			parport_enable_irq(port);
353ed680522SWolfram Sang 		} else {
354c5f3d544SSudip Mukherjee 			dev_warn(&adapter->pdev->dev,
355c5f3d544SSudip Mukherjee 				 "Failed to register ARA client\n");
35635859254SJean Delvare 		}
357ed680522SWolfram Sang 	}
35835859254SJean Delvare 
3591da177e4SLinus Torvalds 	/* Add the new adapter to the list */
36056acc7a3SJean Delvare 	mutex_lock(&adapter_list_lock);
36156acc7a3SJean Delvare 	list_add_tail(&adapter->node, &adapter_list);
36256acc7a3SJean Delvare 	mutex_unlock(&adapter_list_lock);
3631da177e4SLinus Torvalds 	return;
3641da177e4SLinus Torvalds 
36507da0372SJean Delvare  err_unregister:
3667b964f73SJean Delvare 	parport_release(adapter->pdev);
3671da177e4SLinus Torvalds 	parport_unregister_device(adapter->pdev);
36807da0372SJean Delvare  err_free:
3691da177e4SLinus Torvalds 	kfree(adapter);
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds 
i2c_parport_detach(struct parport * port)3721da177e4SLinus Torvalds static void i2c_parport_detach(struct parport *port)
3731da177e4SLinus Torvalds {
37456acc7a3SJean Delvare 	struct i2c_par *adapter, *_n;
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 	/* Walk the list */
37756acc7a3SJean Delvare 	mutex_lock(&adapter_list_lock);
37856acc7a3SJean Delvare 	list_for_each_entry_safe(adapter, _n, &adapter_list, node) {
3791da177e4SLinus Torvalds 		if (adapter->pdev->port == port) {
38035859254SJean Delvare 			if (adapter->ara) {
38135859254SJean Delvare 				parport_disable_irq(port);
38235859254SJean Delvare 				i2c_unregister_device(adapter->ara);
38335859254SJean Delvare 			}
3843af07bd2SJean Delvare 			i2c_del_adapter(&adapter->adapter);
3853af07bd2SJean Delvare 
3861da177e4SLinus Torvalds 			/* Un-init if needed (power off...) */
3871da177e4SLinus Torvalds 			if (adapter_parm[type].init.val)
3881da177e4SLinus Torvalds 				line_set(port, 0, &adapter_parm[type].init);
3891da177e4SLinus Torvalds 
3907b964f73SJean Delvare 			parport_release(adapter->pdev);
3911da177e4SLinus Torvalds 			parport_unregister_device(adapter->pdev);
39256acc7a3SJean Delvare 			list_del(&adapter->node);
3931da177e4SLinus Torvalds 			kfree(adapter);
3941da177e4SLinus Torvalds 		}
3951da177e4SLinus Torvalds 	}
39656acc7a3SJean Delvare 	mutex_unlock(&adapter_list_lock);
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds 
3996c129be8SJean Delvare static struct parport_driver i2c_parport_driver = {
4001da177e4SLinus Torvalds 	.name = "i2c-parport",
4018891f41aSSudip Mukherjee 	.match_port = i2c_parport_attach,
4021da177e4SLinus Torvalds 	.detach = i2c_parport_detach,
4038891f41aSSudip Mukherjee 	.devmodel = true,
4041da177e4SLinus Torvalds };
4059c5b1daaSAndy Shevchenko module_parport_driver(i2c_parport_driver);
4061da177e4SLinus Torvalds 
4077c81c60fSJean Delvare MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
4081da177e4SLinus Torvalds MODULE_DESCRIPTION("I2C bus over parallel port");
4091da177e4SLinus Torvalds MODULE_LICENSE("GPL");
410