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 27 struct 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 42 static 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 48 static 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 54 static 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 60 static 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 68 static 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_mem_region(pd->ioarea->start, size); 131 132 err: 133 kfree(pd); 134 return ret; 135 } 136 137 static int simtec_i2c_remove(struct platform_device *dev) 138 { 139 struct simtec_i2c_data *pd = platform_get_drvdata(dev); 140 141 i2c_del_adapter(&pd->adap); 142 143 iounmap(pd->reg); 144 release_mem_region(pd->ioarea->start, resource_size(pd->ioarea)); 145 kfree(pd); 146 147 return 0; 148 } 149 150 /* device driver */ 151 152 static struct platform_driver simtec_i2c_driver = { 153 .driver = { 154 .name = "simtec-i2c", 155 }, 156 .probe = simtec_i2c_probe, 157 .remove = simtec_i2c_remove, 158 }; 159 160 module_platform_driver(simtec_i2c_driver); 161 162 MODULE_DESCRIPTION("Simtec Generic I2C Bus driver"); 163 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 164 MODULE_LICENSE("GPL"); 165 MODULE_ALIAS("platform:simtec-i2c"); 166