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/init.h>
  24#include <linux/delay.h>
  25#include <linux/platform_device.h>
  26#include <linux/slab.h>
  27#include <linux/io.h>
  28
  29#include <linux/i2c.h>
  30#include <linux/i2c-algo-bit.h>
  31
  32struct simtec_i2c_data {
  33        struct resource         *ioarea;
  34        void __iomem            *reg;
  35        struct i2c_adapter       adap;
  36        struct i2c_algo_bit_data bit;
  37};
  38
  39#define CMD_SET_SDA     (1<<2)
  40#define CMD_SET_SCL     (1<<3)
  41
  42#define STATE_SDA       (1<<0)
  43#define STATE_SCL       (1<<1)
  44
  45/* i2c bit-bus functions */
  46
  47static void simtec_i2c_setsda(void *pw, int state)
  48{
  49        struct simtec_i2c_data *pd = pw;
  50        writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
  51}
  52
  53static void simtec_i2c_setscl(void *pw, int state)
  54{
  55        struct simtec_i2c_data *pd = pw;
  56        writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
  57}
  58
  59static int simtec_i2c_getsda(void *pw)
  60{
  61        struct simtec_i2c_data *pd = pw;
  62        return readb(pd->reg) & STATE_SDA ? 1 : 0;
  63}
  64
  65static int simtec_i2c_getscl(void *pw)
  66{
  67        struct simtec_i2c_data *pd = pw;
  68        return readb(pd->reg) & STATE_SCL ? 1 : 0;
  69}
  70
  71/* device registration */
  72
  73static int simtec_i2c_probe(struct platform_device *dev)
  74{
  75        struct simtec_i2c_data *pd;
  76        struct resource *res;
  77        int size;
  78        int ret;
  79
  80        pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
  81        if (pd == NULL) {
  82                dev_err(&dev->dev, "cannot allocate private data\n");
  83                return -ENOMEM;
  84        }
  85
  86        platform_set_drvdata(dev, pd);
  87
  88        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
  89        if (res == NULL) {
  90                dev_err(&dev->dev, "cannot find IO resource\n");
  91                ret = -ENOENT;
  92                goto err;
  93        }
  94
  95        size = resource_size(res);
  96
  97        pd->ioarea = request_mem_region(res->start, size, dev->name);
  98        if (pd->ioarea == NULL) {
  99                dev_err(&dev->dev, "cannot request IO\n");
 100                ret = -ENXIO;
 101                goto err;
 102        }
 103
 104        pd->reg = ioremap(res->start, size);
 105        if (pd->reg == NULL) {
 106                dev_err(&dev->dev, "cannot map IO\n");
 107                ret = -ENXIO;
 108                goto err_res;
 109        }
 110
 111        /* setup the private data */
 112
 113        pd->adap.owner = THIS_MODULE;
 114        pd->adap.algo_data = &pd->bit;
 115        pd->adap.dev.parent = &dev->dev;
 116
 117        strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
 118
 119        pd->bit.data = pd;
 120        pd->bit.setsda = simtec_i2c_setsda;
 121        pd->bit.setscl = simtec_i2c_setscl;
 122        pd->bit.getsda = simtec_i2c_getsda;
 123        pd->bit.getscl = simtec_i2c_getscl;
 124        pd->bit.timeout = HZ;
 125        pd->bit.udelay = 20;
 126
 127        ret = i2c_bit_add_bus(&pd->adap);
 128        if (ret)
 129                goto err_all;
 130
 131        return 0;
 132
 133 err_all:
 134        iounmap(pd->reg);
 135
 136 err_res:
 137        release_resource(pd->ioarea);
 138        kfree(pd->ioarea);
 139
 140 err:
 141        kfree(pd);
 142        return ret;
 143}
 144
 145static int simtec_i2c_remove(struct platform_device *dev)
 146{
 147        struct simtec_i2c_data *pd = platform_get_drvdata(dev);
 148
 149        i2c_del_adapter(&pd->adap);
 150
 151        iounmap(pd->reg);
 152        release_resource(pd->ioarea);
 153        kfree(pd->ioarea);
 154        kfree(pd);
 155
 156        return 0;
 157}
 158
 159/* device driver */
 160
 161static struct platform_driver simtec_i2c_driver = {
 162        .driver         = {
 163                .name           = "simtec-i2c",
 164                .owner          = THIS_MODULE,
 165        },
 166        .probe          = simtec_i2c_probe,
 167        .remove         = simtec_i2c_remove,
 168};
 169
 170module_platform_driver(simtec_i2c_driver);
 171
 172MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
 173MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
 174MODULE_LICENSE("GPL");
 175MODULE_ALIAS("platform:simtec-i2c");
 176