Path: blob/master/drivers/i2c/busses/i2c-parport.c
15111 views
/* ------------------------------------------------------------------------ *1* i2c-parport.c I2C bus over parallel port *2* ------------------------------------------------------------------------ *3Copyright (C) 2003-2011 Jean Delvare <[email protected]>45Based on older i2c-philips-par.c driver6Copyright (C) 1995-2000 Simon G. Vogl7With some changes from:8Frodo Looijaard <[email protected]>9Kyösti Mälkki <[email protected]>1011This program is free software; you can redistribute it and/or modify12it under the terms of the GNU General Public License as published by13the Free Software Foundation; either version 2 of the License, or14(at your option) any later version.1516This program is distributed in the hope that it will be useful,17but WITHOUT ANY WARRANTY; without even the implied warranty of18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the19GNU General Public License for more details.2021You should have received a copy of the GNU General Public License22along with this program; if not, write to the Free Software23Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.24* ------------------------------------------------------------------------ */2526#include <linux/kernel.h>27#include <linux/module.h>28#include <linux/init.h>29#include <linux/delay.h>30#include <linux/parport.h>31#include <linux/i2c.h>32#include <linux/i2c-algo-bit.h>33#include <linux/i2c-smbus.h>34#include <linux/slab.h>35#include <linux/list.h>36#include <linux/mutex.h>37#include "i2c-parport.h"3839/* ----- Device list ------------------------------------------------------ */4041struct i2c_par {42struct pardevice *pdev;43struct i2c_adapter adapter;44struct i2c_algo_bit_data algo_data;45struct i2c_smbus_alert_setup alert_data;46struct i2c_client *ara;47struct list_head node;48};4950static LIST_HEAD(adapter_list);51static DEFINE_MUTEX(adapter_list_lock);5253/* ----- Low-level parallel port access ----------------------------------- */5455static void port_write_data(struct parport *p, unsigned char d)56{57parport_write_data(p, d);58}5960static void port_write_control(struct parport *p, unsigned char d)61{62parport_write_control(p, d);63}6465static unsigned char port_read_data(struct parport *p)66{67return parport_read_data(p);68}6970static unsigned char port_read_status(struct parport *p)71{72return parport_read_status(p);73}7475static unsigned char port_read_control(struct parport *p)76{77return parport_read_control(p);78}7980static void (* const port_write[])(struct parport *, unsigned char) = {81port_write_data,82NULL,83port_write_control,84};8586static unsigned char (* const port_read[])(struct parport *) = {87port_read_data,88port_read_status,89port_read_control,90};9192/* ----- Unified line operation functions --------------------------------- */9394static inline void line_set(struct parport *data, int state,95const struct lineop *op)96{97u8 oldval = port_read[op->port](data);9899/* Touch only the bit(s) needed */100if ((op->inverted && !state) || (!op->inverted && state))101port_write[op->port](data, oldval | op->val);102else103port_write[op->port](data, oldval & ~op->val);104}105106static inline int line_get(struct parport *data,107const struct lineop *op)108{109u8 oldval = port_read[op->port](data);110111return ((op->inverted && (oldval & op->val) != op->val)112|| (!op->inverted && (oldval & op->val) == op->val));113}114115/* ----- I2C algorithm call-back functions and structures ----------------- */116117static void parport_setscl(void *data, int state)118{119line_set((struct parport *) data, state, &adapter_parm[type].setscl);120}121122static void parport_setsda(void *data, int state)123{124line_set((struct parport *) data, state, &adapter_parm[type].setsda);125}126127static int parport_getscl(void *data)128{129return line_get((struct parport *) data, &adapter_parm[type].getscl);130}131132static int parport_getsda(void *data)133{134return line_get((struct parport *) data, &adapter_parm[type].getsda);135}136137/* Encapsulate the functions above in the correct structure.138Note that this is only a template, from which the real structures are139copied. The attaching code will set getscl to NULL for adapters that140cannot read SCL back, and will also make the data field point to141the parallel port structure. */142static const struct i2c_algo_bit_data parport_algo_data = {143.setsda = parport_setsda,144.setscl = parport_setscl,145.getsda = parport_getsda,146.getscl = parport_getscl,147.udelay = 10, /* ~50 kbps */148.timeout = HZ,149};150151/* ----- I2c and parallel port call-back functions and structures --------- */152153void i2c_parport_irq(void *data)154{155struct i2c_par *adapter = data;156struct i2c_client *ara = adapter->ara;157158if (ara) {159dev_dbg(&ara->dev, "SMBus alert received\n");160i2c_handle_smbus_alert(ara);161} else162dev_dbg(&adapter->adapter.dev,163"SMBus alert received but no ARA client!\n");164}165166static void i2c_parport_attach(struct parport *port)167{168struct i2c_par *adapter;169170adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);171if (adapter == NULL) {172printk(KERN_ERR "i2c-parport: Failed to kzalloc\n");173return;174}175176pr_debug("i2c-parport: attaching to %s\n", port->name);177parport_disable_irq(port);178adapter->pdev = parport_register_device(port, "i2c-parport",179NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);180if (!adapter->pdev) {181printk(KERN_ERR "i2c-parport: Unable to register with parport\n");182goto err_free;183}184185/* Fill the rest of the structure */186adapter->adapter.owner = THIS_MODULE;187adapter->adapter.class = I2C_CLASS_HWMON;188strlcpy(adapter->adapter.name, "Parallel port adapter",189sizeof(adapter->adapter.name));190adapter->algo_data = parport_algo_data;191/* Slow down if we can't sense SCL */192if (!adapter_parm[type].getscl.val) {193adapter->algo_data.getscl = NULL;194adapter->algo_data.udelay = 50; /* ~10 kbps */195}196adapter->algo_data.data = port;197adapter->adapter.algo_data = &adapter->algo_data;198adapter->adapter.dev.parent = port->physport->dev;199200if (parport_claim_or_block(adapter->pdev) < 0) {201printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");202goto err_unregister;203}204205/* Reset hardware to a sane state (SCL and SDA high) */206parport_setsda(port, 1);207parport_setscl(port, 1);208/* Other init if needed (power on...) */209if (adapter_parm[type].init.val) {210line_set(port, 1, &adapter_parm[type].init);211/* Give powered devices some time to settle */212msleep(100);213}214215if (i2c_bit_add_bus(&adapter->adapter) < 0) {216printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");217goto err_unregister;218}219220/* Setup SMBus alert if supported */221if (adapter_parm[type].smbus_alert) {222adapter->alert_data.alert_edge_triggered = 1;223adapter->ara = i2c_setup_smbus_alert(&adapter->adapter,224&adapter->alert_data);225if (adapter->ara)226parport_enable_irq(port);227else228printk(KERN_WARNING "i2c-parport: Failed to register "229"ARA client\n");230}231232/* Add the new adapter to the list */233mutex_lock(&adapter_list_lock);234list_add_tail(&adapter->node, &adapter_list);235mutex_unlock(&adapter_list_lock);236return;237238err_unregister:239parport_release(adapter->pdev);240parport_unregister_device(adapter->pdev);241err_free:242kfree(adapter);243}244245static void i2c_parport_detach(struct parport *port)246{247struct i2c_par *adapter, *_n;248249/* Walk the list */250mutex_lock(&adapter_list_lock);251list_for_each_entry_safe(adapter, _n, &adapter_list, node) {252if (adapter->pdev->port == port) {253if (adapter->ara) {254parport_disable_irq(port);255i2c_unregister_device(adapter->ara);256}257i2c_del_adapter(&adapter->adapter);258259/* Un-init if needed (power off...) */260if (adapter_parm[type].init.val)261line_set(port, 0, &adapter_parm[type].init);262263parport_release(adapter->pdev);264parport_unregister_device(adapter->pdev);265list_del(&adapter->node);266kfree(adapter);267}268}269mutex_unlock(&adapter_list_lock);270}271272static struct parport_driver i2c_parport_driver = {273.name = "i2c-parport",274.attach = i2c_parport_attach,275.detach = i2c_parport_detach,276};277278/* ----- Module loading, unloading and information ------------------------ */279280static int __init i2c_parport_init(void)281{282if (type < 0) {283printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");284return -ENODEV;285}286287if (type >= ARRAY_SIZE(adapter_parm)) {288printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);289return -ENODEV;290}291292return parport_register_driver(&i2c_parport_driver);293}294295static void __exit i2c_parport_exit(void)296{297parport_unregister_driver(&i2c_parport_driver);298}299300MODULE_AUTHOR("Jean Delvare <[email protected]>");301MODULE_DESCRIPTION("I2C bus over parallel port");302MODULE_LICENSE("GPL");303304module_init(i2c_parport_init);305module_exit(i2c_parport_exit);306307308