Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: Add atmel-hlcdc driver

The HLCDC IP available on some Atmel SoCs (i.e. at91sam9n12, at91sam9x5
family or sama5d3 family) exposes 2 subdevices:
- a display controller (controlled by a DRM driver)
- a PWM chip

The MFD device provides a regmap and several clocks (those connected
to this hardware block) to its subdevices.

This way concurrent accesses to the iomem range are handled by the regmap
framework, and each subdevice can safely access HLCDC registers.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Tested-by: Anthony Harivel <anthony.harivel@emtrion.de>
Tested-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Boris Brezillon and committed by
Lee Jones
2c86e9fb 6e3f62f0

+214
+6
drivers/mfd/Kconfig
··· 59 59 additional drivers must be enabled in order to use the 60 60 functionality of the device. 61 61 62 + config MFD_ATMEL_HLCDC 63 + tristate 64 + select MFD_CORE 65 + select REGMAP_MMIO 66 + depends on OF 67 + 62 68 config MFD_BCM590XX 63 69 tristate "Broadcom BCM590xx PMUs" 64 70 select MFD_CORE
+1
drivers/mfd/Makefile
··· 157 157 obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o 158 158 obj-$(CONFIG_MFD_TPS65090) += tps65090.o 159 159 obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o 160 + obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o 160 161 obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o 161 162 obj-$(CONFIG_MFD_PALMAS) += palmas.o 162 163 obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
+122
drivers/mfd/atmel-hlcdc.c
··· 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/mfd/atmel-hlcdc.h> 22 + #include <linux/mfd/core.h> 23 + #include <linux/module.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/regmap.h> 26 + 27 + #define ATMEL_HLCDC_REG_MAX (0x4000 - 0x4) 28 + 29 + static const struct mfd_cell atmel_hlcdc_cells[] = { 30 + { 31 + .name = "atmel-hlcdc-pwm", 32 + .of_compatible = "atmel,hlcdc-pwm", 33 + }, 34 + { 35 + .name = "atmel-hlcdc-dc", 36 + .of_compatible = "atmel,hlcdc-display-controller", 37 + }, 38 + }; 39 + 40 + static const struct regmap_config atmel_hlcdc_regmap_config = { 41 + .reg_bits = 32, 42 + .val_bits = 32, 43 + .reg_stride = 4, 44 + .max_register = ATMEL_HLCDC_REG_MAX, 45 + }; 46 + 47 + static int atmel_hlcdc_probe(struct platform_device *pdev) 48 + { 49 + struct device *dev = &pdev->dev; 50 + struct atmel_hlcdc *hlcdc; 51 + struct resource *res; 52 + void __iomem *regs; 53 + 54 + hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL); 55 + if (!hlcdc) 56 + return -ENOMEM; 57 + 58 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 59 + regs = devm_ioremap_resource(dev, res); 60 + if (IS_ERR(regs)) 61 + return PTR_ERR(regs); 62 + 63 + hlcdc->irq = platform_get_irq(pdev, 0); 64 + if (hlcdc->irq < 0) 65 + return hlcdc->irq; 66 + 67 + hlcdc->periph_clk = devm_clk_get(dev, "periph_clk"); 68 + if (IS_ERR(hlcdc->periph_clk)) { 69 + dev_err(dev, "failed to get peripheral clock\n"); 70 + return PTR_ERR(hlcdc->periph_clk); 71 + } 72 + 73 + hlcdc->sys_clk = devm_clk_get(dev, "sys_clk"); 74 + if (IS_ERR(hlcdc->sys_clk)) { 75 + dev_err(dev, "failed to get system clock\n"); 76 + return PTR_ERR(hlcdc->sys_clk); 77 + } 78 + 79 + hlcdc->slow_clk = devm_clk_get(dev, "slow_clk"); 80 + if (IS_ERR(hlcdc->slow_clk)) { 81 + dev_err(dev, "failed to get slow clock\n"); 82 + return PTR_ERR(hlcdc->slow_clk); 83 + } 84 + 85 + hlcdc->regmap = devm_regmap_init_mmio(dev, regs, 86 + &atmel_hlcdc_regmap_config); 87 + if (IS_ERR(hlcdc->regmap)) 88 + return PTR_ERR(hlcdc->regmap); 89 + 90 + dev_set_drvdata(dev, hlcdc); 91 + 92 + return mfd_add_devices(dev, -1, atmel_hlcdc_cells, 93 + ARRAY_SIZE(atmel_hlcdc_cells), 94 + NULL, 0, NULL); 95 + } 96 + 97 + static int atmel_hlcdc_remove(struct platform_device *pdev) 98 + { 99 + mfd_remove_devices(&pdev->dev); 100 + 101 + return 0; 102 + } 103 + 104 + static const struct of_device_id atmel_hlcdc_match[] = { 105 + { .compatible = "atmel,sama5d3-hlcdc" }, 106 + { /* sentinel */ }, 107 + }; 108 + 109 + static struct platform_driver atmel_hlcdc_driver = { 110 + .probe = atmel_hlcdc_probe, 111 + .remove = atmel_hlcdc_remove, 112 + .driver = { 113 + .name = "atmel-hlcdc", 114 + .of_match_table = atmel_hlcdc_match, 115 + }, 116 + }; 117 + module_platform_driver(atmel_hlcdc_driver); 118 + 119 + MODULE_ALIAS("platform:atmel-hlcdc"); 120 + MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>"); 121 + MODULE_DESCRIPTION("Atmel HLCDC driver"); 122 + MODULE_LICENSE("GPL v2");
+85
include/linux/mfd/atmel-hlcdc.h
··· 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 + #ifndef __LINUX_MFD_HLCDC_H 21 + #define __LINUX_MFD_HLCDC_H 22 + 23 + #include <linux/clk.h> 24 + #include <linux/regmap.h> 25 + 26 + #define ATMEL_HLCDC_CFG(i) ((i) * 0x4) 27 + #define ATMEL_HLCDC_SIG_CFG LCDCFG(5) 28 + #define ATMEL_HLCDC_HSPOL BIT(0) 29 + #define ATMEL_HLCDC_VSPOL BIT(1) 30 + #define ATMEL_HLCDC_VSPDLYS BIT(2) 31 + #define ATMEL_HLCDC_VSPDLYE BIT(3) 32 + #define ATMEL_HLCDC_DISPPOL BIT(4) 33 + #define ATMEL_HLCDC_DITHER BIT(6) 34 + #define ATMEL_HLCDC_DISPDLY BIT(7) 35 + #define ATMEL_HLCDC_MODE_MASK GENMASK(9, 8) 36 + #define ATMEL_HLCDC_PP BIT(10) 37 + #define ATMEL_HLCDC_VSPSU BIT(12) 38 + #define ATMEL_HLCDC_VSPHO BIT(13) 39 + #define ATMEL_HLCDC_GUARDTIME_MASK GENMASK(20, 16) 40 + 41 + #define ATMEL_HLCDC_EN 0x20 42 + #define ATMEL_HLCDC_DIS 0x24 43 + #define ATMEL_HLCDC_SR 0x28 44 + #define ATMEL_HLCDC_IER 0x2c 45 + #define ATMEL_HLCDC_IDR 0x30 46 + #define ATMEL_HLCDC_IMR 0x34 47 + #define ATMEL_HLCDC_ISR 0x38 48 + 49 + #define ATMEL_HLCDC_CLKPOL BIT(0) 50 + #define ATMEL_HLCDC_CLKSEL BIT(2) 51 + #define ATMEL_HLCDC_CLKPWMSEL BIT(3) 52 + #define ATMEL_HLCDC_CGDIS(i) BIT(8 + (i)) 53 + #define ATMEL_HLCDC_CLKDIV_SHFT 16 54 + #define ATMEL_HLCDC_CLKDIV_MASK GENMASK(23, 16) 55 + #define ATMEL_HLCDC_CLKDIV(div) ((div - 2) << ATMEL_HLCDC_CLKDIV_SHFT) 56 + 57 + #define ATMEL_HLCDC_PIXEL_CLK BIT(0) 58 + #define ATMEL_HLCDC_SYNC BIT(1) 59 + #define ATMEL_HLCDC_DISP BIT(2) 60 + #define ATMEL_HLCDC_PWM BIT(3) 61 + #define ATMEL_HLCDC_SIP BIT(4) 62 + 63 + #define ATMEL_HLCDC_SOF BIT(0) 64 + #define ATMEL_HLCDC_SYNCDIS BIT(1) 65 + #define ATMEL_HLCDC_FIFOERR BIT(4) 66 + #define ATMEL_HLCDC_LAYER_STATUS(x) BIT((x) + 8) 67 + 68 + /** 69 + * Structure shared by the MFD device and its subdevices. 70 + * 71 + * @regmap: register map used to access HLCDC IP registers 72 + * @periph_clk: the hlcdc peripheral clock 73 + * @sys_clk: the hlcdc system clock 74 + * @slow_clk: the system slow clk 75 + * @irq: the hlcdc irq 76 + */ 77 + struct atmel_hlcdc { 78 + struct regmap *regmap; 79 + struct clk *periph_clk; 80 + struct clk *sys_clk; 81 + struct clk *slow_clk; 82 + int irq; 83 + }; 84 + 85 + #endif /* __LINUX_MFD_HLCDC_H */