linux/drivers/i2c/busses/i2c-simtec.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005 Simtec Electronics
   3 *      Ben Dooks <ben@simtec.co.uk>
   4 *
   5 * Simtec Generic I2C Controller
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU General Public License
  17 * along with this program; if not, write to the Free Software
  18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19*/
  20
  21#include <linux/kernel.h>
  22#include <linux/module.h>
  23#include <linux/delay.h>
  24#include <linux/platform_device.h>
  25#include <linux/slab.h>
  26#include <linux/io.h>
  27
  28#include <linux/i2c.h>
  29#include <linux/i2c-algo-bit.h>
  30
  31struct simtec_i2c_data {
  32        struct resource         *ioarea;
  33        void __iomem            *reg;
  34        struct i2c_adapter       adap;
  35        struct i2c_algo_bit_data bit;
  36};
  37
  38#define CMD_SET_SDA     (1<<2)
  39#define CMD_SET_SCL     (1<<3)
  40
  41#define STATE_SDA       (1<<0)
  42#define STATE_SCL       (1<<1)
  43
  44/* i2c bit-bus functions */
  45
  46static void simtec_i2c_setsda(void *pw, int state)
  47{
  48        struct simtec_i2c_data *pd = pw;
  49        writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
  50}
  51
  52static void simtec_i2c_setscl(void *pw, int state)
  53{
  54        struct simtec_i2c_data *pd = pw;
  55        writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
  56}
  57
  58static int simtec_i2c_getsda(void *pw)
  59{
  60        struct simtec_i2c_data *pd = pw;
  61        return readb(pd->reg) & STATE_SDA ? 1 : 0;
  62}
  63
  64static int simtec_i2c_getscl(void *pw)
  65{
  66        struct simtec_i2c_data *pd = pw;
  67        return readb(pd->reg) & STATE_SCL ? 1 : 0;
  68}
  69
  70/* device registration */
  71
  72static int simtec_i2c_probe(struct platform_device *dev)
  73{
  74        struct simtec_i2c_data *pd;
  75        struct resource *res;
  76        int size;
  77        int ret;
  78
  79        pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
  80        if (pd == NULL)
  81                return -ENOMEM;
  82
  83        platform_set_drvdata(dev, pd);
  84
  85        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
  86        if (res == NULL) {
  87                dev_err(&dev->dev, "cannot find IO resource\n");
  88                ret = -ENOENT;
  89                goto err;
  90        }
  91
  92        size = resource_size(res);
  93
  94        pd->ioarea = request_mem_region(res->start, size, dev->name);
  95        if (pd->ioarea == NULL) {
  96                dev_err(&dev->dev, "cannot request IO\n");
  97                ret = -ENXIO;
  98                goto err;
  99        }
 100
 101        pd->reg = ioremap(res->start, size);
 102        if (pd->reg == NULL) {
 103                dev_err(&dev->dev, "cannot map IO\n");
 104                ret = -ENXIO;
 105                goto err_res;
 106        }
 107
 108        /* setup the private data */
 109
 110        pd->adap.owner = THIS_MODULE;
 111        pd->adap.algo_data = &pd->bit;
 112        pd->adap.dev.parent = &dev->dev;
 113
 114        strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
 115
 116        pd->bit.data = pd;
 117        pd->bit.setsda = simtec_i2c_setsda;
 118        pd->bit.setscl = simtec_i2c_setscl;
 119        pd->bit.getsda = simtec_i2c_getsda;
 120        pd->bit.getscl = simtec_i2c_getscl;
 121        pd->bit.timeout = HZ;
 122        pd->bit.udelay = 20;
 123
 124        ret = i2c_bit_add_bus(&pd->adap);
 125        if (ret)
 126                goto err_all;
 127
 128        return 0;
 129
 130 err_all:
 131        iounmap(pd->reg);
 132
 133 err_res:
 134        release_resource(pd->ioarea);
 135        kfree(pd->ioarea);
 136
 137 err:
 138        kfree(pd);
 139        return ret;
 140}
 141
 142static int simtec_i2c_remove(struct platform_device *dev)
 143{
 144        struct simtec_i2c_data *pd = platform_get_drvdata(dev);
 145
 146        i2c_del_adapter(&pd->adap);
 147
 148        iounmap(pd->reg);
 149        release_resource(pd->ioarea);
 150        kfree(pd->ioarea);
 151        kfree(pd);
 152
 153        return 0;
 154}
 155
 156/* device driver */
 157
 158static struct platform_driver simtec_i2c_driver = {
 159        .driver         = {
 160                .name           = "simtec-i2c",
 161                .owner          = THIS_MODULE,
 162        },
 163        .probe          = simtec_i2c_probe,
 164        .remove         = simtec_i2c_remove,
 165};
 166
 167module_platform_driver(simtec_i2c_driver);
 168
 169MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
 170MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 171MODULE_LICENSE("GPL");
 172MODULE_ALIAS("platform:simtec-i2c");
 173