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

atmel-hlcdc.c (3968B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014 Free Electrons
      4 * Copyright (C) 2014 Atmel
      5 *
      6 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
      7 */
      8
      9#include <linux/clk.h>
     10#include <linux/iopoll.h>
     11#include <linux/mfd/atmel-hlcdc.h>
     12#include <linux/mfd/core.h>
     13#include <linux/module.h>
     14#include <linux/mod_devicetable.h>
     15#include <linux/platform_device.h>
     16#include <linux/regmap.h>
     17
     18#define ATMEL_HLCDC_REG_MAX		(0x4000 - 0x4)
     19
     20struct atmel_hlcdc_regmap {
     21	void __iomem *regs;
     22	struct device *dev;
     23};
     24
     25static const struct mfd_cell atmel_hlcdc_cells[] = {
     26	{
     27		.name = "atmel-hlcdc-pwm",
     28		.of_compatible = "atmel,hlcdc-pwm",
     29	},
     30	{
     31		.name = "atmel-hlcdc-dc",
     32		.of_compatible = "atmel,hlcdc-display-controller",
     33	},
     34};
     35
     36static int regmap_atmel_hlcdc_reg_write(void *context, unsigned int reg,
     37					unsigned int val)
     38{
     39	struct atmel_hlcdc_regmap *hregmap = context;
     40
     41	if (reg <= ATMEL_HLCDC_DIS) {
     42		u32 status;
     43		int ret;
     44
     45		ret = readl_poll_timeout_atomic(hregmap->regs + ATMEL_HLCDC_SR,
     46						status,
     47						!(status & ATMEL_HLCDC_SIP),
     48						1, 100);
     49		if (ret) {
     50			dev_err(hregmap->dev,
     51				"Timeout! Clock domain synchronization is in progress!\n");
     52			return ret;
     53		}
     54	}
     55
     56	writel(val, hregmap->regs + reg);
     57
     58	return 0;
     59}
     60
     61static int regmap_atmel_hlcdc_reg_read(void *context, unsigned int reg,
     62				       unsigned int *val)
     63{
     64	struct atmel_hlcdc_regmap *hregmap = context;
     65
     66	*val = readl(hregmap->regs + reg);
     67
     68	return 0;
     69}
     70
     71static const struct regmap_config atmel_hlcdc_regmap_config = {
     72	.reg_bits = 32,
     73	.val_bits = 32,
     74	.reg_stride = 4,
     75	.max_register = ATMEL_HLCDC_REG_MAX,
     76	.reg_write = regmap_atmel_hlcdc_reg_write,
     77	.reg_read = regmap_atmel_hlcdc_reg_read,
     78	.fast_io = true,
     79};
     80
     81static int atmel_hlcdc_probe(struct platform_device *pdev)
     82{
     83	struct atmel_hlcdc_regmap *hregmap;
     84	struct device *dev = &pdev->dev;
     85	struct atmel_hlcdc *hlcdc;
     86	struct resource *res;
     87
     88	hregmap = devm_kzalloc(dev, sizeof(*hregmap), GFP_KERNEL);
     89	if (!hregmap)
     90		return -ENOMEM;
     91
     92	hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL);
     93	if (!hlcdc)
     94		return -ENOMEM;
     95
     96	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     97	hregmap->regs = devm_ioremap_resource(dev, res);
     98	if (IS_ERR(hregmap->regs))
     99		return PTR_ERR(hregmap->regs);
    100
    101	hregmap->dev = &pdev->dev;
    102
    103	hlcdc->irq = platform_get_irq(pdev, 0);
    104	if (hlcdc->irq < 0)
    105		return hlcdc->irq;
    106
    107	hlcdc->periph_clk = devm_clk_get(dev, "periph_clk");
    108	if (IS_ERR(hlcdc->periph_clk)) {
    109		dev_err(dev, "failed to get peripheral clock\n");
    110		return PTR_ERR(hlcdc->periph_clk);
    111	}
    112
    113	hlcdc->sys_clk = devm_clk_get(dev, "sys_clk");
    114	if (IS_ERR(hlcdc->sys_clk)) {
    115		dev_err(dev, "failed to get system clock\n");
    116		return PTR_ERR(hlcdc->sys_clk);
    117	}
    118
    119	hlcdc->slow_clk = devm_clk_get(dev, "slow_clk");
    120	if (IS_ERR(hlcdc->slow_clk)) {
    121		dev_err(dev, "failed to get slow clock\n");
    122		return PTR_ERR(hlcdc->slow_clk);
    123	}
    124
    125	hlcdc->regmap = devm_regmap_init(dev, NULL, hregmap,
    126					 &atmel_hlcdc_regmap_config);
    127	if (IS_ERR(hlcdc->regmap))
    128		return PTR_ERR(hlcdc->regmap);
    129
    130	dev_set_drvdata(dev, hlcdc);
    131
    132	return devm_mfd_add_devices(dev, -1, atmel_hlcdc_cells,
    133				    ARRAY_SIZE(atmel_hlcdc_cells),
    134				    NULL, 0, NULL);
    135}
    136
    137static const struct of_device_id atmel_hlcdc_match[] = {
    138	{ .compatible = "atmel,at91sam9n12-hlcdc" },
    139	{ .compatible = "atmel,at91sam9x5-hlcdc" },
    140	{ .compatible = "atmel,sama5d2-hlcdc" },
    141	{ .compatible = "atmel,sama5d3-hlcdc" },
    142	{ .compatible = "atmel,sama5d4-hlcdc" },
    143	{ .compatible = "microchip,sam9x60-hlcdc" },
    144	{ /* sentinel */ },
    145};
    146MODULE_DEVICE_TABLE(of, atmel_hlcdc_match);
    147
    148static struct platform_driver atmel_hlcdc_driver = {
    149	.probe = atmel_hlcdc_probe,
    150	.driver = {
    151		.name = "atmel-hlcdc",
    152		.of_match_table = atmel_hlcdc_match,
    153	},
    154};
    155module_platform_driver(atmel_hlcdc_driver);
    156
    157MODULE_ALIAS("platform:atmel-hlcdc");
    158MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
    159MODULE_DESCRIPTION("Atmel HLCDC driver");
    160MODULE_LICENSE("GPL v2");