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/pm.h> 40 #include <linux/io.h> 41 #include <linux/slab.h> 42 #include "i2c-designware-core.h" 43 44 static struct i2c_algorithm i2c_dw_algo = { 45 .master_xfer = i2c_dw_xfer, 46 .functionality = i2c_dw_func, 47 }; 48 static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) 49 { 50 return clk_get_rate(dev->clk)/1000; 51 } 52 53 static int __devinit dw_i2c_probe(struct platform_device *pdev) 54 { 55 struct dw_i2c_dev *dev; 56 struct i2c_adapter *adap; 57 struct resource *mem, *ioarea; 58 int irq, r; 59 60 /* NOTE: driver uses the static register mapping */ 61 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 62 if (!mem) { 63 dev_err(&pdev->dev, "no mem resource?\n"); 64 return -EINVAL; 65 } 66 67 irq = platform_get_irq(pdev, 0); 68 if (irq < 0) { 69 dev_err(&pdev->dev, "no irq resource?\n"); 70 return irq; /* -ENXIO */ 71 } 72 73 ioarea = request_mem_region(mem->start, resource_size(mem), 74 pdev->name); 75 if (!ioarea) { 76 dev_err(&pdev->dev, "I2C region already claimed\n"); 77 return -EBUSY; 78 } 79 80 dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); 81 if (!dev) { 82 r = -ENOMEM; 83 goto err_release_region; 84 } 85 86 init_completion(&dev->cmd_complete); 87 mutex_init(&dev->lock); 88 dev->dev = get_device(&pdev->dev); 89 dev->irq = irq; 90 platform_set_drvdata(pdev, dev); 91 92 dev->clk = clk_get(&pdev->dev, NULL); 93 dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; 94 95 if (IS_ERR(dev->clk)) { 96 r = -ENODEV; 97 goto err_free_mem; 98 } 99 clk_prepare_enable(dev->clk); 100 101 dev->functionality = 102 I2C_FUNC_I2C | 103 I2C_FUNC_10BIT_ADDR | 104 I2C_FUNC_SMBUS_BYTE | 105 I2C_FUNC_SMBUS_BYTE_DATA | 106 I2C_FUNC_SMBUS_WORD_DATA | 107 I2C_FUNC_SMBUS_I2C_BLOCK; 108 dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | 109 DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; 110 111 dev->base = ioremap(mem->start, resource_size(mem)); 112 if (dev->base == NULL) { 113 dev_err(&pdev->dev, "failure mapping io resources\n"); 114 r = -EBUSY; 115 goto err_unuse_clocks; 116 } 117 { 118 u32 param1 = i2c_dw_read_comp_param(dev); 119 120 dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; 121 dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; 122 } 123 r = i2c_dw_init(dev); 124 if (r) 125 goto err_iounmap; 126 127 i2c_dw_disable_int(dev); 128 r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev); 129 if (r) { 130 dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); 131 goto err_iounmap; 132 } 133 134 adap = &dev->adapter; 135 i2c_set_adapdata(adap, dev); 136 adap->owner = THIS_MODULE; 137 adap->class = I2C_CLASS_HWMON; 138 strlcpy(adap->name, "Synopsys DesignWare I2C adapter", 139 sizeof(adap->name)); 140 adap->algo = &i2c_dw_algo; 141 adap->dev.parent = &pdev->dev; 142 adap->dev.of_node = pdev->dev.of_node; 143 144 adap->nr = pdev->id; 145 r = i2c_add_numbered_adapter(adap); 146 if (r) { 147 dev_err(&pdev->dev, "failure adding adapter\n"); 148 goto err_free_irq; 149 } 150 of_i2c_register_devices(adap); 151 152 return 0; 153 154 err_free_irq: 155 free_irq(dev->irq, dev); 156 err_iounmap: 157 iounmap(dev->base); 158 err_unuse_clocks: 159 clk_disable_unprepare(dev->clk); 160 clk_put(dev->clk); 161 dev->clk = NULL; 162 err_free_mem: 163 platform_set_drvdata(pdev, NULL); 164 put_device(&pdev->dev); 165 kfree(dev); 166 err_release_region: 167 release_mem_region(mem->start, resource_size(mem)); 168 169 return r; 170 } 171 172 static int __devexit dw_i2c_remove(struct platform_device *pdev) 173 { 174 struct dw_i2c_dev *dev = platform_get_drvdata(pdev); 175 struct resource *mem; 176 177 platform_set_drvdata(pdev, NULL); 178 i2c_del_adapter(&dev->adapter); 179 put_device(&pdev->dev); 180 181 clk_disable_unprepare(dev->clk); 182 clk_put(dev->clk); 183 dev->clk = NULL; 184 185 i2c_dw_disable(dev); 186 free_irq(dev->irq, dev); 187 kfree(dev); 188 189 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 190 release_mem_region(mem->start, resource_size(mem)); 191 return 0; 192 } 193 194 #ifdef CONFIG_OF 195 static const struct of_device_id dw_i2c_of_match[] = { 196 { .compatible = "snps,designware-i2c", }, 197 {}, 198 }; 199 MODULE_DEVICE_TABLE(of, dw_i2c_of_match); 200 #endif 201 202 #ifdef CONFIG_PM 203 static int dw_i2c_suspend(struct device *dev) 204 { 205 struct platform_device *pdev = to_platform_device(dev); 206 struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); 207 208 clk_disable_unprepare(i_dev->clk); 209 210 return 0; 211 } 212 213 static int dw_i2c_resume(struct device *dev) 214 { 215 struct platform_device *pdev = to_platform_device(dev); 216 struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); 217 218 clk_prepare_enable(i_dev->clk); 219 i2c_dw_init(i_dev); 220 221 return 0; 222 } 223 #endif 224 225 static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume); 226 227 /* work with hotplug and coldplug */ 228 MODULE_ALIAS("platform:i2c_designware"); 229 230 static struct platform_driver dw_i2c_driver = { 231 .remove = __devexit_p(dw_i2c_remove), 232 .driver = { 233 .name = "i2c_designware", 234 .owner = THIS_MODULE, 235 .of_match_table = of_match_ptr(dw_i2c_of_match), 236 .pm = &dw_i2c_dev_pm_ops, 237 }, 238 }; 239 240 static int __init dw_i2c_init_driver(void) 241 { 242 return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe); 243 } 244 subsys_initcall(dw_i2c_init_driver); 245 246 static void __exit dw_i2c_exit_driver(void) 247 { 248 platform_driver_unregister(&dw_i2c_driver); 249 } 250 module_exit(dw_i2c_exit_driver); 251 252 MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); 253 MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter"); 254 MODULE_LICENSE("GPL"); 255