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

mfd: atmel-flexcom: Add a driver for Atmel Flexible Serial Communication Unit

This driver supports the new Atmel Flexcom. The Flexcom is a wrapper which
integrates one SPI controller, one I2C controller and one USART. Only one
function can be enabled at a time. This driver selects the function once
for all, when the Flexcom is probed, according to the value of the new
"atmel,flexcom-mode" device tree property.

This driver has chosen to present the Flexcom to the system as a MFD so
the implementation is seamless for the existing Atmel SPI, I2C and USART
drivers.

Also the Flexcom embeds FIFOs: the latest patches of the SPI, I2C and
USART drivers take advantage of this new feature.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Cyrille Pitchen and committed by
Lee Jones
5c41f11c c335bd5d

+116
+11
drivers/mfd/Kconfig
··· 60 60 additional drivers must be enabled in order to use the 61 61 functionality of the device. 62 62 63 + config MFD_ATMEL_FLEXCOM 64 + tristate "Atmel Flexcom (Flexible Serial Communication Unit)" 65 + select MFD_CORE 66 + depends on OF 67 + help 68 + Select this to get support for Atmel Flexcom. This is a wrapper 69 + which embeds a SPI controller, a I2C controller and a USART. Only 70 + one function can be used at a time. The choice is done at boot time 71 + by the probe function of this MFD driver according to a device tree 72 + property. 73 + 63 74 config MFD_ATMEL_HLCDC 64 75 tristate "Atmel HLCDC (High-end LCD Controller)" 65 76 select MFD_CORE
+1
drivers/mfd/Makefile
··· 164 164 obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o 165 165 obj-$(CONFIG_MFD_TPS65090) += tps65090.o 166 166 obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o 167 + obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o 167 168 obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o 168 169 obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o 169 170 obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o
+104
drivers/mfd/atmel-flexcom.c
··· 1 + /* 2 + * Driver for Atmel Flexcom 3 + * 4 + * Copyright (C) 2015 Atmel Corporation 5 + * 6 + * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + * This program is distributed in the hope that it will be useful, but WITHOUT 13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 + * more details. 16 + * 17 + * You should have received a copy of the GNU General Public License along with 18 + * this program. If not, see <http://www.gnu.org/licenses/>. 19 + */ 20 + 21 + #include <linux/module.h> 22 + #include <linux/types.h> 23 + #include <linux/kernel.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/of.h> 26 + #include <linux/of_platform.h> 27 + #include <linux/err.h> 28 + #include <linux/io.h> 29 + #include <linux/clk.h> 30 + #include <dt-bindings/mfd/atmel-flexcom.h> 31 + 32 + /* I/O register offsets */ 33 + #define FLEX_MR 0x0 /* Mode Register */ 34 + #define FLEX_VERSION 0xfc /* Version Register */ 35 + 36 + /* Mode Register bit fields */ 37 + #define FLEX_MR_OPMODE_OFFSET (0) /* Operating Mode */ 38 + #define FLEX_MR_OPMODE_MASK (0x3 << FLEX_MR_OPMODE_OFFSET) 39 + #define FLEX_MR_OPMODE(opmode) (((opmode) << FLEX_MR_OPMODE_OFFSET) & \ 40 + FLEX_MR_OPMODE_MASK) 41 + 42 + 43 + static int atmel_flexcom_probe(struct platform_device *pdev) 44 + { 45 + struct device_node *np = pdev->dev.of_node; 46 + struct clk *clk; 47 + struct resource *res; 48 + void __iomem *base; 49 + u32 opmode; 50 + int err; 51 + 52 + err = of_property_read_u32(np, "atmel,flexcom-mode", &opmode); 53 + if (err) 54 + return err; 55 + 56 + if (opmode < ATMEL_FLEXCOM_MODE_USART || 57 + opmode > ATMEL_FLEXCOM_MODE_TWI) 58 + return -EINVAL; 59 + 60 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 61 + base = devm_ioremap_resource(&pdev->dev, res); 62 + if (IS_ERR(base)) 63 + return PTR_ERR(base); 64 + 65 + clk = devm_clk_get(&pdev->dev, NULL); 66 + if (IS_ERR(clk)) 67 + return PTR_ERR(clk); 68 + 69 + err = clk_prepare_enable(clk); 70 + if (err) 71 + return err; 72 + 73 + /* 74 + * Set the Operating Mode in the Mode Register: only the selected device 75 + * is clocked. Hence, registers of the other serial devices remain 76 + * inaccessible and are read as zero. Also the external I/O lines of the 77 + * Flexcom are muxed to reach the selected device. 78 + */ 79 + writel(FLEX_MR_OPMODE(opmode), base + FLEX_MR); 80 + 81 + clk_disable_unprepare(clk); 82 + 83 + return of_platform_populate(np, NULL, NULL, &pdev->dev); 84 + } 85 + 86 + static const struct of_device_id atmel_flexcom_of_match[] = { 87 + { .compatible = "atmel,sama5d2-flexcom" }, 88 + { /* sentinel */ } 89 + }; 90 + MODULE_DEVICE_TABLE(of, atmel_flexcom_of_match); 91 + 92 + static struct platform_driver atmel_flexcom_driver = { 93 + .probe = atmel_flexcom_probe, 94 + .driver = { 95 + .name = "atmel_flexcom", 96 + .of_match_table = atmel_flexcom_of_match, 97 + }, 98 + }; 99 + 100 + module_platform_driver(atmel_flexcom_driver); 101 + 102 + MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@atmel.com>"); 103 + MODULE_DESCRIPTION("Atmel Flexcom MFD driver"); 104 + MODULE_LICENSE("GPL v2");