1 /* 2 * Synopsys DesignWare I2C adapter driver (master only). 3 * 4 * Based on the TI DAVINCI I2C adapter driver. 5 * 6 * Copyright (C) 2006 Texas Instruments. 7 * Copyright (C) 2007 MontaVista Software Inc. 8 * Copyright (C) 2009 Provigent Ltd. 9 * 10 * ---------------------------------------------------------------------------- 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * ---------------------------------------------------------------------------- 26 * 27 */ 28 #include <linux/kernel.h> 29 #include <linux/module.h> 30 #include <linux/delay.h> 31 #include <linux/i2c.h> 32 #include <linux/clk.h> 33 #include <linux/errno.h> 34 #include <linux/sched.h> 35 #include <linux/err.h> 36 #include <linux/interrupt.h> 37 #include <linux/of_i2c.h> 38 #include <linux/platform_device.h> 39 #include <linux/io.h> 40 #include <linux/slab.h> 41 #include "i2c-designware-core.h" 42 43 static struct i2c_algorithm i2c_dw_algo = { 44 .master_xfer = i2c_dw_xfer, 45 .functionality = i2c_dw_func, 46 }; 47 static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) 48 { 49 return clk_get_rate(dev->clk)/1000; 50 } 51 52 static int __devinit dw_i2c_probe(struct platform_device *pdev) 53 { 54 struct dw_i2c_dev *dev; 55 struct i2c_adapter *adap; 56 struct resource *mem, *ioarea; 57 int irq, r; 58 59 /* NOTE: driver uses the static register mapping */ 60 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 61 if (!mem) { 62 dev_err(&pdev->dev, "no mem resource?\n"); 63 return -EINVAL; 64 } 65 66 irq = platform_get_irq(pdev, 0); 67 if (irq < 0) { 68 dev_err(&pdev->dev, "no irq resource?\n"); 69 return irq; /* -ENXIO */ 70 } 71 72 ioarea = request_mem_region(mem->start, resource_size(mem), 73 pdev->name); 74 if (!ioarea) { 75 dev_err(&pdev->dev, "I2C region already claimed\n"); 76 return -EBUSY; 77 } 78 79 dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); 80 if (!dev) { 81 r = -ENOMEM; 82 goto err_release_region; 83 } 84 85 init_completion(&dev->cmd_complete); 86 mutex_init(&dev->lock); 87 dev->dev = get_device(&pdev->dev); 88 dev->irq = irq; 89 platform_set_drvdata(pdev, dev); 90 91 dev->clk = clk_get(&pdev->dev, NULL); 92 dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; 93 94 if (IS_ERR(dev->clk)) { 95 r = -ENODEV; 96 goto err_free_mem; 97 } 98 clk_enable(dev->clk); 99 100 dev->functionality = 101 I2C_FUNC_I2C | 102 I2C_FUNC_10BIT_ADDR | 103 I2C_FUNC_SMBUS_BYTE | 104 I2C_FUNC_SMBUS_BYTE_DATA | 105 I2C_FUNC_SMBUS_WORD_DATA | 106 I2C_FUNC_SMBUS_I2C_BLOCK; 107 dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | 108 DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; 109 110 dev->base = ioremap(mem->start, resource_size(mem)); 111 if (dev->base == NULL) { 112 dev_err(&pdev->dev, "failure mapping io resources\n"); 113 r = -EBUSY; 114 goto err_unuse_clocks; 115 } 116 { 117 u32 param1 = i2c_dw_read_comp_param(dev); 118 119 dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; 120 dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; 121 } 122 r = i2c_dw_init(dev); 123 if (r) 124 goto err_iounmap; 125 126 i2c_dw_disable_int(dev); 127 r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev); 128 if (r) { 129 dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); 130 goto err_iounmap; 131 } 132 133 adap = &dev->adapter; 134 i2c_set_adapdata(adap, dev); 135 adap->owner = THIS_MODULE; 136 adap->class = I2C_CLASS_HWMON; 137 strlcpy(adap->name, "Synopsys DesignWare I2C adapter", 138 sizeof(adap->name)); 139 adap->algo = &i2c_dw_algo; 140 adap->dev.parent = &pdev->dev; 141 adap->dev.of_node = pdev->dev.of_node; 142 143 adap->nr = pdev->id; 144 r = i2c_add_numbered_adapter(adap); 145 if (r) { 146 dev_err(&pdev->dev, "failure adding adapter\n"); 147 goto err_free_irq; 148 } 149 of_i2c_register_devices(adap); 150 151 return 0; 152 153 err_free_irq: 154 free_irq(dev->irq, dev); 155 err_iounmap: 156 iounmap(dev->base); 157 err_unuse_clocks: 158 clk_disable(dev->clk); 159 clk_put(dev->clk); 160 dev->clk = NULL; 161 err_free_mem: 162 platform_set_drvdata(pdev, NULL); 163 put_device(&pdev->dev); 164 kfree(dev); 165 err_release_region: 166 release_mem_region(mem->start, resource_size(mem)); 167 168 return r; 169 } 170 171 static int __devexit dw_i2c_remove(struct platform_device *pdev) 172 { 173 struct dw_i2c_dev *dev = platform_get_drvdata(pdev); 174 struct resource *mem; 175 176 platform_set_drvdata(pdev, NULL); 177 i2c_del_adapter(&dev->adapter); 178 put_device(&pdev->dev); 179 180 clk_disable(dev->clk); 181 clk_put(dev->clk); 182 dev->clk = NULL; 183 184 i2c_dw_disable(dev); 185 free_irq(dev->irq, dev); 186 kfree(dev); 187 188 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 189 release_mem_region(mem->start, resource_size(mem)); 190 return 0; 191 } 192 193 #ifdef CONFIG_OF 194 static const struct of_device_id dw_i2c_of_match[] = { 195 { .compatible = "snps,designware-i2c", }, 196 {}, 197 }; 198 MODULE_DEVICE_TABLE(of, dw_i2c_of_match); 199 #endif 200 201 /* work with hotplug and coldplug */ 202 MODULE_ALIAS("platform:i2c_designware"); 203 204 static struct platform_driver dw_i2c_driver = { 205 .remove = __devexit_p(dw_i2c_remove), 206 .driver = { 207 .name = "i2c_designware", 208 .owner = THIS_MODULE, 209 .of_match_table = of_match_ptr(dw_i2c_of_match), 210 }, 211 }; 212 213 static int __init dw_i2c_init_driver(void) 214 { 215 return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe); 216 } 217 subsys_initcall(dw_i2c_init_driver); 218 219 static void __exit dw_i2c_exit_driver(void) 220 { 221 platform_driver_unregister(&dw_i2c_driver); 222 } 223 module_exit(dw_i2c_exit_driver); 224 225 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); 226 MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter"); 227 MODULE_LICENSE("GPL"); 228