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