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