linux/drivers/i2c/busses/i2c-parport.c
<<
>>
Prefs
   1/* ------------------------------------------------------------------------ *
   2 * i2c-parport.c I2C bus over parallel port                                 *
   3 * ------------------------------------------------------------------------ *
   4   Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org>
   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>
  10   Kyösti Mälkki <kmalkki@cc.hut.fi>
  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
  27#include <linux/kernel.h>
  28#include <linux/module.h>
  29#include <linux/init.h>
  30#include <linux/delay.h>
  31#include <linux/parport.h>
  32#include <linux/i2c.h>
  33#include <linux/i2c-algo-bit.h>
  34#include <linux/i2c-smbus.h>
  35#include <linux/slab.h>
  36#include <linux/list.h>
  37#include <linux/mutex.h>
  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;
  46        struct i2c_smbus_alert_setup alert_data;
  47        struct i2c_client *ara;
  48        struct list_head node;
  49};
  50
  51static LIST_HEAD(adapter_list);
  52static DEFINE_MUTEX(adapter_list_lock);
  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
 141   cannot read SCL back, and will also make the data field point to
 142   the parallel port structure. */
 143static const struct i2c_algo_bit_data parport_algo_data = {
 144        .setsda         = parport_setsda,
 145        .setscl         = parport_setscl,
 146        .getsda         = parport_getsda,
 147        .getscl         = parport_getscl,
 148        .udelay         = 10, /* ~50 kbps */
 149        .timeout        = HZ,
 150}; 
 151
 152/* ----- I2c and parallel port call-back functions and structures --------- */
 153
 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
 167static void i2c_parport_attach (struct parport *port)
 168{
 169        struct i2c_par *adapter;
 170        
 171        adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
 172        if (adapter == NULL) {
 173                printk(KERN_ERR "i2c-parport: Failed to kzalloc\n");
 174                return;
 175        }
 176
 177        pr_debug("i2c-parport: attaching to %s\n", port->name);
 178        parport_disable_irq(port);
 179        adapter->pdev = parport_register_device(port, "i2c-parport",
 180                NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
 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 */
 187        adapter->adapter.owner = THIS_MODULE;
 188        adapter->adapter.class = I2C_CLASS_HWMON;
 189        strlcpy(adapter->adapter.name, "Parallel port adapter",
 190                sizeof(adapter->adapter.name));
 191        adapter->algo_data = parport_algo_data;
 192        /* Slow down if we can't sense SCL */
 193        if (!adapter_parm[type].getscl.val) {
 194                adapter->algo_data.getscl = NULL;
 195                adapter->algo_data.udelay = 50; /* ~10 kbps */
 196        }
 197        adapter->algo_data.data = port;
 198        adapter->adapter.algo_data = &adapter->algo_data;
 199        adapter->adapter.dev.parent = port->physport->dev;
 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...) */
 210        if (adapter_parm[type].init.val) {
 211                line_set(port, 1, &adapter_parm[type].init);
 212                /* Give powered devices some time to settle */
 213                msleep(100);
 214        }
 215
 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
 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
 233        /* Add the new adapter to the list */
 234        mutex_lock(&adapter_list_lock);
 235        list_add_tail(&adapter->node, &adapter_list);
 236        mutex_unlock(&adapter_list_lock);
 237        return;
 238
 239ERROR1:
 240        parport_release(adapter->pdev);
 241        parport_unregister_device(adapter->pdev);
 242ERROR0:
 243        kfree(adapter);
 244}
 245
 246static void i2c_parport_detach (struct parport *port)
 247{
 248        struct i2c_par *adapter, *_n;
 249
 250        /* Walk the list */
 251        mutex_lock(&adapter_list_lock);
 252        list_for_each_entry_safe(adapter, _n, &adapter_list, node) {
 253                if (adapter->pdev->port == port) {
 254                        if (adapter->ara) {
 255                                parport_disable_irq(port);
 256                                i2c_unregister_device(adapter->ara);
 257                        }
 258                        i2c_del_adapter(&adapter->adapter);
 259
 260                        /* Un-init if needed (power off...) */
 261                        if (adapter_parm[type].init.val)
 262                                line_set(port, 0, &adapter_parm[type].init);
 263                                
 264                        parport_release(adapter->pdev);
 265                        parport_unregister_device(adapter->pdev);
 266                        list_del(&adapter->node);
 267                        kfree(adapter);
 268                }
 269        }
 270        mutex_unlock(&adapter_list_lock);
 271}
 272
 273static struct parport_driver i2c_parport_driver = {
 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{
 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)) {
 289                printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
 290                return -ENODEV;
 291        }
 292
 293        return parport_register_driver(&i2c_parport_driver);
 294}
 295
 296static void __exit i2c_parport_exit(void)
 297{
 298        parport_unregister_driver(&i2c_parport_driver);
 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);
 307