root/drivers/i2c/busses/i2c-at91-core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. at91_twi_read
  2. at91_twi_write
  3. at91_disable_twi_interrupts
  4. at91_twi_irq_save
  5. at91_twi_irq_restore
  6. at91_init_twi_bus
  7. at91_twi_get_driver_data
  8. at91_twi_probe
  9. at91_twi_remove
  10. at91_twi_runtime_suspend
  11. at91_twi_runtime_resume
  12. at91_twi_suspend_noirq
  13. at91_twi_resume_noirq
  14. at91_twi_init
  15. at91_twi_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *  i2c Support for Atmel's AT91 Two-Wire Interface (TWI)
   4  *
   5  *  Copyright (C) 2011 Weinmann Medical GmbH
   6  *  Author: Nikolaus Voss <n.voss@weinmann.de>
   7  *
   8  *  Evolved from original work by:
   9  *  Copyright (C) 2004 Rick Bronson
  10  *  Converted to 2.6 by Andrew Victor <andrew@sanpeople.com>
  11  *
  12  *  Borrowed heavily from original work by:
  13  *  Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
  14  */
  15 
  16 #include <linux/clk.h>
  17 #include <linux/err.h>
  18 #include <linux/i2c.h>
  19 #include <linux/io.h>
  20 #include <linux/module.h>
  21 #include <linux/of.h>
  22 #include <linux/of_device.h>
  23 #include <linux/platform_device.h>
  24 #include <linux/pm_runtime.h>
  25 #include <linux/pinctrl/consumer.h>
  26 
  27 #include "i2c-at91.h"
  28 
  29 unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg)
  30 {
  31         return readl_relaxed(dev->base + reg);
  32 }
  33 
  34 void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val)
  35 {
  36         writel_relaxed(val, dev->base + reg);
  37 }
  38 
  39 void at91_disable_twi_interrupts(struct at91_twi_dev *dev)
  40 {
  41         at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK);
  42 }
  43 
  44 void at91_twi_irq_save(struct at91_twi_dev *dev)
  45 {
  46         dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & AT91_TWI_INT_MASK;
  47         at91_disable_twi_interrupts(dev);
  48 }
  49 
  50 void at91_twi_irq_restore(struct at91_twi_dev *dev)
  51 {
  52         at91_twi_write(dev, AT91_TWI_IER, dev->imr);
  53 }
  54 
  55 void at91_init_twi_bus(struct at91_twi_dev *dev)
  56 {
  57         at91_disable_twi_interrupts(dev);
  58         at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST);
  59         if (dev->slave_detected)
  60                 at91_init_twi_bus_slave(dev);
  61         else
  62                 at91_init_twi_bus_master(dev);
  63 }
  64 
  65 static struct at91_twi_pdata at91rm9200_config = {
  66         .clk_max_div = 5,
  67         .clk_offset = 3,
  68         .has_unre_flag = true,
  69         .has_alt_cmd = false,
  70         .has_hold_field = false,
  71 };
  72 
  73 static struct at91_twi_pdata at91sam9261_config = {
  74         .clk_max_div = 5,
  75         .clk_offset = 4,
  76         .has_unre_flag = false,
  77         .has_alt_cmd = false,
  78         .has_hold_field = false,
  79 };
  80 
  81 static struct at91_twi_pdata at91sam9260_config = {
  82         .clk_max_div = 7,
  83         .clk_offset = 4,
  84         .has_unre_flag = false,
  85         .has_alt_cmd = false,
  86         .has_hold_field = false,
  87 };
  88 
  89 static struct at91_twi_pdata at91sam9g20_config = {
  90         .clk_max_div = 7,
  91         .clk_offset = 4,
  92         .has_unre_flag = false,
  93         .has_alt_cmd = false,
  94         .has_hold_field = false,
  95 };
  96 
  97 static struct at91_twi_pdata at91sam9g10_config = {
  98         .clk_max_div = 7,
  99         .clk_offset = 4,
 100         .has_unre_flag = false,
 101         .has_alt_cmd = false,
 102         .has_hold_field = false,
 103 };
 104 
 105 static const struct platform_device_id at91_twi_devtypes[] = {
 106         {
 107                 .name = "i2c-at91rm9200",
 108                 .driver_data = (unsigned long) &at91rm9200_config,
 109         }, {
 110                 .name = "i2c-at91sam9261",
 111                 .driver_data = (unsigned long) &at91sam9261_config,
 112         }, {
 113                 .name = "i2c-at91sam9260",
 114                 .driver_data = (unsigned long) &at91sam9260_config,
 115         }, {
 116                 .name = "i2c-at91sam9g20",
 117                 .driver_data = (unsigned long) &at91sam9g20_config,
 118         }, {
 119                 .name = "i2c-at91sam9g10",
 120                 .driver_data = (unsigned long) &at91sam9g10_config,
 121         }, {
 122                 /* sentinel */
 123         }
 124 };
 125 
 126 #if defined(CONFIG_OF)
 127 static struct at91_twi_pdata at91sam9x5_config = {
 128         .clk_max_div = 7,
 129         .clk_offset = 4,
 130         .has_unre_flag = false,
 131         .has_alt_cmd = false,
 132         .has_hold_field = false,
 133 };
 134 
 135 static struct at91_twi_pdata sama5d4_config = {
 136         .clk_max_div = 7,
 137         .clk_offset = 4,
 138         .has_unre_flag = false,
 139         .has_alt_cmd = false,
 140         .has_hold_field = true,
 141 };
 142 
 143 static struct at91_twi_pdata sama5d2_config = {
 144         .clk_max_div = 7,
 145         .clk_offset = 3,
 146         .has_unre_flag = true,
 147         .has_alt_cmd = true,
 148         .has_hold_field = true,
 149 };
 150 
 151 static const struct of_device_id atmel_twi_dt_ids[] = {
 152         {
 153                 .compatible = "atmel,at91rm9200-i2c",
 154                 .data = &at91rm9200_config,
 155         }, {
 156                 .compatible = "atmel,at91sam9260-i2c",
 157                 .data = &at91sam9260_config,
 158         }, {
 159                 .compatible = "atmel,at91sam9261-i2c",
 160                 .data = &at91sam9261_config,
 161         }, {
 162                 .compatible = "atmel,at91sam9g20-i2c",
 163                 .data = &at91sam9g20_config,
 164         }, {
 165                 .compatible = "atmel,at91sam9g10-i2c",
 166                 .data = &at91sam9g10_config,
 167         }, {
 168                 .compatible = "atmel,at91sam9x5-i2c",
 169                 .data = &at91sam9x5_config,
 170         }, {
 171                 .compatible = "atmel,sama5d4-i2c",
 172                 .data = &sama5d4_config,
 173         }, {
 174                 .compatible = "atmel,sama5d2-i2c",
 175                 .data = &sama5d2_config,
 176         }, {
 177                 /* sentinel */
 178         }
 179 };
 180 MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids);
 181 #endif
 182 
 183 static struct at91_twi_pdata *at91_twi_get_driver_data(
 184                                         struct platform_device *pdev)
 185 {
 186         if (pdev->dev.of_node) {
 187                 const struct of_device_id *match;
 188                 match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node);
 189                 if (!match)
 190                         return NULL;
 191                 return (struct at91_twi_pdata *)match->data;
 192         }
 193         return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data;
 194 }
 195 
 196 static int at91_twi_probe(struct platform_device *pdev)
 197 {
 198         struct at91_twi_dev *dev;
 199         struct resource *mem;
 200         int rc;
 201         u32 phy_addr;
 202 
 203         dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
 204         if (!dev)
 205                 return -ENOMEM;
 206 
 207         dev->dev = &pdev->dev;
 208 
 209         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 210         if (!mem)
 211                 return -ENODEV;
 212         phy_addr = mem->start;
 213 
 214         dev->pdata = at91_twi_get_driver_data(pdev);
 215         if (!dev->pdata)
 216                 return -ENODEV;
 217 
 218         dev->base = devm_ioremap_resource(&pdev->dev, mem);
 219         if (IS_ERR(dev->base))
 220                 return PTR_ERR(dev->base);
 221 
 222         dev->irq = platform_get_irq(pdev, 0);
 223         if (dev->irq < 0)
 224                 return dev->irq;
 225 
 226         platform_set_drvdata(pdev, dev);
 227 
 228         dev->clk = devm_clk_get(dev->dev, NULL);
 229         if (IS_ERR(dev->clk)) {
 230                 dev_err(dev->dev, "no clock defined\n");
 231                 return -ENODEV;
 232         }
 233         clk_prepare_enable(dev->clk);
 234 
 235         snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
 236         i2c_set_adapdata(&dev->adapter, dev);
 237         dev->adapter.owner = THIS_MODULE;
 238         dev->adapter.class = I2C_CLASS_DEPRECATED;
 239         dev->adapter.dev.parent = dev->dev;
 240         dev->adapter.nr = pdev->id;
 241         dev->adapter.timeout = AT91_I2C_TIMEOUT;
 242         dev->adapter.dev.of_node = pdev->dev.of_node;
 243 
 244         dev->slave_detected = i2c_detect_slave_mode(&pdev->dev);
 245 
 246         if (dev->slave_detected)
 247                 rc = at91_twi_probe_slave(pdev, phy_addr, dev);
 248         else
 249                 rc = at91_twi_probe_master(pdev, phy_addr, dev);
 250         if (rc)
 251                 return rc;
 252 
 253         at91_init_twi_bus(dev);
 254 
 255         pm_runtime_set_autosuspend_delay(dev->dev, AUTOSUSPEND_TIMEOUT);
 256         pm_runtime_use_autosuspend(dev->dev);
 257         pm_runtime_set_active(dev->dev);
 258         pm_runtime_enable(dev->dev);
 259 
 260         rc = i2c_add_numbered_adapter(&dev->adapter);
 261         if (rc) {
 262                 clk_disable_unprepare(dev->clk);
 263 
 264                 pm_runtime_disable(dev->dev);
 265                 pm_runtime_set_suspended(dev->dev);
 266 
 267                 return rc;
 268         }
 269 
 270         dev_info(dev->dev, "AT91 i2c bus driver (hw version: %#x).\n",
 271                  at91_twi_read(dev, AT91_TWI_VER));
 272         return 0;
 273 }
 274 
 275 static int at91_twi_remove(struct platform_device *pdev)
 276 {
 277         struct at91_twi_dev *dev = platform_get_drvdata(pdev);
 278 
 279         i2c_del_adapter(&dev->adapter);
 280         clk_disable_unprepare(dev->clk);
 281 
 282         pm_runtime_disable(dev->dev);
 283         pm_runtime_set_suspended(dev->dev);
 284 
 285         return 0;
 286 }
 287 
 288 #ifdef CONFIG_PM
 289 
 290 static int at91_twi_runtime_suspend(struct device *dev)
 291 {
 292         struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
 293 
 294         clk_disable_unprepare(twi_dev->clk);
 295 
 296         pinctrl_pm_select_sleep_state(dev);
 297 
 298         return 0;
 299 }
 300 
 301 static int at91_twi_runtime_resume(struct device *dev)
 302 {
 303         struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
 304 
 305         pinctrl_pm_select_default_state(dev);
 306 
 307         return clk_prepare_enable(twi_dev->clk);
 308 }
 309 
 310 static int at91_twi_suspend_noirq(struct device *dev)
 311 {
 312         if (!pm_runtime_status_suspended(dev))
 313                 at91_twi_runtime_suspend(dev);
 314 
 315         return 0;
 316 }
 317 
 318 static int at91_twi_resume_noirq(struct device *dev)
 319 {
 320         struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
 321         int ret;
 322 
 323         if (!pm_runtime_status_suspended(dev)) {
 324                 ret = at91_twi_runtime_resume(dev);
 325                 if (ret)
 326                         return ret;
 327         }
 328 
 329         pm_runtime_mark_last_busy(dev);
 330         pm_request_autosuspend(dev);
 331 
 332         at91_init_twi_bus(twi_dev);
 333 
 334         return 0;
 335 }
 336 
 337 static const struct dev_pm_ops at91_twi_pm = {
 338         .suspend_noirq  = at91_twi_suspend_noirq,
 339         .resume_noirq   = at91_twi_resume_noirq,
 340         .runtime_suspend        = at91_twi_runtime_suspend,
 341         .runtime_resume         = at91_twi_runtime_resume,
 342 };
 343 
 344 #define at91_twi_pm_ops (&at91_twi_pm)
 345 #else
 346 #define at91_twi_pm_ops NULL
 347 #endif
 348 
 349 static struct platform_driver at91_twi_driver = {
 350         .probe          = at91_twi_probe,
 351         .remove         = at91_twi_remove,
 352         .id_table       = at91_twi_devtypes,
 353         .driver         = {
 354                 .name   = "at91_i2c",
 355                 .of_match_table = of_match_ptr(atmel_twi_dt_ids),
 356                 .pm     = at91_twi_pm_ops,
 357         },
 358 };
 359 
 360 static int __init at91_twi_init(void)
 361 {
 362         return platform_driver_register(&at91_twi_driver);
 363 }
 364 
 365 static void __exit at91_twi_exit(void)
 366 {
 367         platform_driver_unregister(&at91_twi_driver);
 368 }
 369 
 370 subsys_initcall(at91_twi_init);
 371 module_exit(at91_twi_exit);
 372 
 373 MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
 374 MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");
 375 MODULE_LICENSE("GPL");
 376 MODULE_ALIAS("platform:at91_i2c");

/* [<][>][^][v][top][bottom][index][help] */