Path: blob/master/drivers/i2c/busses/i2c-pca-platform.c
15111 views
/*1* i2c_pca_platform.c2*3* Platform driver for the PCA9564 I2C controller.4*5* Copyright (C) 2008 Pengutronix6*7* This program is free software; you can redistribute it and/or modify8* it under the terms of the GNU General Public License version 2 as9* published by the Free Software Foundation.1011*/12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/init.h>15#include <linux/slab.h>16#include <linux/delay.h>17#include <linux/jiffies.h>18#include <linux/errno.h>19#include <linux/i2c.h>20#include <linux/interrupt.h>21#include <linux/platform_device.h>22#include <linux/i2c-algo-pca.h>23#include <linux/i2c-pca-platform.h>24#include <linux/gpio.h>25#include <linux/io.h>2627#include <asm/irq.h>2829struct i2c_pca_pf_data {30void __iomem *reg_base;31int irq; /* if 0, use polling */32int gpio;33wait_queue_head_t wait;34struct i2c_adapter adap;35struct i2c_algo_pca_data algo_data;36unsigned long io_base;37unsigned long io_size;38};3940/* Read/Write functions for different register alignments */4142static int i2c_pca_pf_readbyte8(void *pd, int reg)43{44struct i2c_pca_pf_data *i2c = pd;45return ioread8(i2c->reg_base + reg);46}4748static int i2c_pca_pf_readbyte16(void *pd, int reg)49{50struct i2c_pca_pf_data *i2c = pd;51return ioread8(i2c->reg_base + reg * 2);52}5354static int i2c_pca_pf_readbyte32(void *pd, int reg)55{56struct i2c_pca_pf_data *i2c = pd;57return ioread8(i2c->reg_base + reg * 4);58}5960static void i2c_pca_pf_writebyte8(void *pd, int reg, int val)61{62struct i2c_pca_pf_data *i2c = pd;63iowrite8(val, i2c->reg_base + reg);64}6566static void i2c_pca_pf_writebyte16(void *pd, int reg, int val)67{68struct i2c_pca_pf_data *i2c = pd;69iowrite8(val, i2c->reg_base + reg * 2);70}7172static void i2c_pca_pf_writebyte32(void *pd, int reg, int val)73{74struct i2c_pca_pf_data *i2c = pd;75iowrite8(val, i2c->reg_base + reg * 4);76}777879static int i2c_pca_pf_waitforcompletion(void *pd)80{81struct i2c_pca_pf_data *i2c = pd;82unsigned long timeout;83long ret;8485if (i2c->irq) {86ret = wait_event_timeout(i2c->wait,87i2c->algo_data.read_byte(i2c, I2C_PCA_CON)88& I2C_PCA_CON_SI, i2c->adap.timeout);89} else {90/* Do polling */91timeout = jiffies + i2c->adap.timeout;92do {93ret = time_before(jiffies, timeout);94if (i2c->algo_data.read_byte(i2c, I2C_PCA_CON)95& I2C_PCA_CON_SI)96break;97udelay(100);98} while (ret);99}100101return ret > 0;102}103104static void i2c_pca_pf_dummyreset(void *pd)105{106struct i2c_pca_pf_data *i2c = pd;107printk(KERN_WARNING "%s: No reset-pin found. Chip may get stuck!\n",108i2c->adap.name);109}110111static void i2c_pca_pf_resetchip(void *pd)112{113struct i2c_pca_pf_data *i2c = pd;114115gpio_set_value(i2c->gpio, 0);116ndelay(100);117gpio_set_value(i2c->gpio, 1);118}119120static irqreturn_t i2c_pca_pf_handler(int this_irq, void *dev_id)121{122struct i2c_pca_pf_data *i2c = dev_id;123124if ((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)125return IRQ_NONE;126127wake_up(&i2c->wait);128129return IRQ_HANDLED;130}131132133static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)134{135struct i2c_pca_pf_data *i2c;136struct resource *res;137struct i2c_pca9564_pf_platform_data *platform_data =138pdev->dev.platform_data;139int ret = 0;140int irq;141142res = platform_get_resource(pdev, IORESOURCE_MEM, 0);143irq = platform_get_irq(pdev, 0);144/* If irq is 0, we do polling. */145146if (res == NULL) {147ret = -ENODEV;148goto e_print;149}150151if (!request_mem_region(res->start, resource_size(res), res->name)) {152ret = -ENOMEM;153goto e_print;154}155156i2c = kzalloc(sizeof(struct i2c_pca_pf_data), GFP_KERNEL);157if (!i2c) {158ret = -ENOMEM;159goto e_alloc;160}161162init_waitqueue_head(&i2c->wait);163164i2c->reg_base = ioremap(res->start, resource_size(res));165if (!i2c->reg_base) {166ret = -ENOMEM;167goto e_remap;168}169i2c->io_base = res->start;170i2c->io_size = resource_size(res);171i2c->irq = irq;172173i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;174i2c->adap.owner = THIS_MODULE;175snprintf(i2c->adap.name, sizeof(i2c->adap.name),176"PCA9564/PCA9665 at 0x%08lx",177(unsigned long) res->start);178i2c->adap.algo_data = &i2c->algo_data;179i2c->adap.dev.parent = &pdev->dev;180181if (platform_data) {182i2c->adap.timeout = platform_data->timeout;183i2c->algo_data.i2c_clock = platform_data->i2c_clock_speed;184i2c->gpio = platform_data->gpio;185} else {186i2c->adap.timeout = HZ;187i2c->algo_data.i2c_clock = 59000;188i2c->gpio = -1;189}190191i2c->algo_data.data = i2c;192i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion;193i2c->algo_data.reset_chip = i2c_pca_pf_dummyreset;194195switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {196case IORESOURCE_MEM_32BIT:197i2c->algo_data.write_byte = i2c_pca_pf_writebyte32;198i2c->algo_data.read_byte = i2c_pca_pf_readbyte32;199break;200case IORESOURCE_MEM_16BIT:201i2c->algo_data.write_byte = i2c_pca_pf_writebyte16;202i2c->algo_data.read_byte = i2c_pca_pf_readbyte16;203break;204case IORESOURCE_MEM_8BIT:205default:206i2c->algo_data.write_byte = i2c_pca_pf_writebyte8;207i2c->algo_data.read_byte = i2c_pca_pf_readbyte8;208break;209}210211/* Use gpio_is_valid() when in mainline */212if (i2c->gpio > -1) {213ret = gpio_request(i2c->gpio, i2c->adap.name);214if (ret == 0) {215gpio_direction_output(i2c->gpio, 1);216i2c->algo_data.reset_chip = i2c_pca_pf_resetchip;217} else {218printk(KERN_WARNING "%s: Registering gpio failed!\n",219i2c->adap.name);220i2c->gpio = ret;221}222}223224if (irq) {225ret = request_irq(irq, i2c_pca_pf_handler,226IRQF_TRIGGER_FALLING, pdev->name, i2c);227if (ret)228goto e_reqirq;229}230231if (i2c_pca_add_numbered_bus(&i2c->adap) < 0) {232ret = -ENODEV;233goto e_adapt;234}235236platform_set_drvdata(pdev, i2c);237238printk(KERN_INFO "%s registered.\n", i2c->adap.name);239240return 0;241242e_adapt:243if (irq)244free_irq(irq, i2c);245e_reqirq:246if (i2c->gpio > -1)247gpio_free(i2c->gpio);248249iounmap(i2c->reg_base);250e_remap:251kfree(i2c);252e_alloc:253release_mem_region(res->start, resource_size(res));254e_print:255printk(KERN_ERR "Registering PCA9564/PCA9665 FAILED! (%d)\n", ret);256return ret;257}258259static int __devexit i2c_pca_pf_remove(struct platform_device *pdev)260{261struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev);262platform_set_drvdata(pdev, NULL);263264i2c_del_adapter(&i2c->adap);265266if (i2c->irq)267free_irq(i2c->irq, i2c);268269if (i2c->gpio > -1)270gpio_free(i2c->gpio);271272iounmap(i2c->reg_base);273release_mem_region(i2c->io_base, i2c->io_size);274kfree(i2c);275276return 0;277}278279static struct platform_driver i2c_pca_pf_driver = {280.probe = i2c_pca_pf_probe,281.remove = __devexit_p(i2c_pca_pf_remove),282.driver = {283.name = "i2c-pca-platform",284.owner = THIS_MODULE,285},286};287288static int __init i2c_pca_pf_init(void)289{290return platform_driver_register(&i2c_pca_pf_driver);291}292293static void __exit i2c_pca_pf_exit(void)294{295platform_driver_unregister(&i2c_pca_pf_driver);296}297298MODULE_AUTHOR("Wolfram Sang <[email protected]>");299MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver");300MODULE_LICENSE("GPL");301302module_init(i2c_pca_pf_init);303module_exit(i2c_pca_pf_exit);304305306307