cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

i2c-at91-core.c (8605B)


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