Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Copyright (C) 2014 Free Electrons
  3 * Copyright (C) 2014 Atmel
  4 *
  5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
  6 *
  7 * This program is free software; you can redistribute it and/or modify it
  8 * under the terms of the GNU General Public License version 2 as published by
  9 * the Free Software Foundation.
 10 *
 11 * This program is distributed in the hope that it will be useful, but WITHOUT
 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 14 * more details.
 15 *
 16 * You should have received a copy of the GNU General Public License along with
 17 * this program.  If not, see <http://www.gnu.org/licenses/>.
 18 */
 19
 20#include <linux/clk.h>
 21#include <linux/iopoll.h>
 22#include <linux/mfd/atmel-hlcdc.h>
 23#include <linux/mfd/core.h>
 24#include <linux/module.h>
 25#include <linux/platform_device.h>
 26#include <linux/regmap.h>
 27
 28#define ATMEL_HLCDC_REG_MAX		(0x4000 - 0x4)
 29
 30struct atmel_hlcdc_regmap {
 31	void __iomem *regs;
 32};
 33
 34static const struct mfd_cell atmel_hlcdc_cells[] = {
 35	{
 36		.name = "atmel-hlcdc-pwm",
 37		.of_compatible = "atmel,hlcdc-pwm",
 38	},
 39	{
 40		.name = "atmel-hlcdc-dc",
 41		.of_compatible = "atmel,hlcdc-display-controller",
 42	},
 43};
 44
 45static int regmap_atmel_hlcdc_reg_write(void *context, unsigned int reg,
 46					unsigned int val)
 47{
 48	struct atmel_hlcdc_regmap *hregmap = context;
 49
 50	if (reg <= ATMEL_HLCDC_DIS) {
 51		u32 status;
 52
 53		readl_poll_timeout_atomic(hregmap->regs + ATMEL_HLCDC_SR,
 54					  status, !(status & ATMEL_HLCDC_SIP),
 55					  1, 100);
 56	}
 57
 58	writel(val, hregmap->regs + reg);
 59
 60	return 0;
 61}
 62
 63static int regmap_atmel_hlcdc_reg_read(void *context, unsigned int reg,
 64				       unsigned int *val)
 65{
 66	struct atmel_hlcdc_regmap *hregmap = context;
 67
 68	*val = readl(hregmap->regs + reg);
 69
 70	return 0;
 71}
 72
 73static const struct regmap_config atmel_hlcdc_regmap_config = {
 74	.reg_bits = 32,
 75	.val_bits = 32,
 76	.reg_stride = 4,
 77	.max_register = ATMEL_HLCDC_REG_MAX,
 78	.reg_write = regmap_atmel_hlcdc_reg_write,
 79	.reg_read = regmap_atmel_hlcdc_reg_read,
 80	.fast_io = true,
 81};
 82
 83static int atmel_hlcdc_probe(struct platform_device *pdev)
 84{
 85	struct atmel_hlcdc_regmap *hregmap;
 86	struct device *dev = &pdev->dev;
 87	struct atmel_hlcdc *hlcdc;
 88	struct resource *res;
 89
 90	hregmap = devm_kzalloc(dev, sizeof(*hregmap), GFP_KERNEL);
 91	if (!hregmap)
 92		return -ENOMEM;
 93
 94	hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL);
 95	if (!hlcdc)
 96		return -ENOMEM;
 97
 98	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 99	hregmap->regs = devm_ioremap_resource(dev, res);
100	if (IS_ERR(hregmap->regs))
101		return PTR_ERR(hregmap->regs);
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	{ /* sentinel */ },
144};
145MODULE_DEVICE_TABLE(of, atmel_hlcdc_match);
146
147static struct platform_driver atmel_hlcdc_driver = {
148	.probe = atmel_hlcdc_probe,
149	.driver = {
150		.name = "atmel-hlcdc",
151		.of_match_table = atmel_hlcdc_match,
152	},
153};
154module_platform_driver(atmel_hlcdc_driver);
155
156MODULE_ALIAS("platform:atmel-hlcdc");
157MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
158MODULE_DESCRIPTION("Atmel HLCDC driver");
159MODULE_LICENSE("GPL v2");