18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Limited
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
88c2ecf20Sopenharmony_ci#include <linux/err.h>
98c2ecf20Sopenharmony_ci#include <linux/io.h>
108c2ecf20Sopenharmony_ci#include <linux/mfd/core.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_data/syscon.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/stat.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define SYS_ID			0x000
198c2ecf20Sopenharmony_ci#define SYS_SW			0x004
208c2ecf20Sopenharmony_ci#define SYS_LED			0x008
218c2ecf20Sopenharmony_ci#define SYS_100HZ		0x024
228c2ecf20Sopenharmony_ci#define SYS_FLAGSSET		0x030
238c2ecf20Sopenharmony_ci#define SYS_FLAGSCLR		0x034
248c2ecf20Sopenharmony_ci#define SYS_NVFLAGS		0x038
258c2ecf20Sopenharmony_ci#define SYS_NVFLAGSSET		0x038
268c2ecf20Sopenharmony_ci#define SYS_NVFLAGSCLR		0x03c
278c2ecf20Sopenharmony_ci#define SYS_MCI			0x048
288c2ecf20Sopenharmony_ci#define SYS_FLASH		0x04c
298c2ecf20Sopenharmony_ci#define SYS_CFGSW		0x058
308c2ecf20Sopenharmony_ci#define SYS_24MHZ		0x05c
318c2ecf20Sopenharmony_ci#define SYS_MISC		0x060
328c2ecf20Sopenharmony_ci#define SYS_DMA			0x064
338c2ecf20Sopenharmony_ci#define SYS_PROCID0		0x084
348c2ecf20Sopenharmony_ci#define SYS_PROCID1		0x088
358c2ecf20Sopenharmony_ci#define SYS_CFGDATA		0x0a0
368c2ecf20Sopenharmony_ci#define SYS_CFGCTRL		0x0a4
378c2ecf20Sopenharmony_ci#define SYS_CFGSTAT		0x0a8
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* The sysreg block is just a random collection of various functions... */
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic struct bgpio_pdata vexpress_sysreg_sys_led_pdata = {
428c2ecf20Sopenharmony_ci	.label = "sys_led",
438c2ecf20Sopenharmony_ci	.base = -1,
448c2ecf20Sopenharmony_ci	.ngpio = 8,
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic struct bgpio_pdata vexpress_sysreg_sys_mci_pdata = {
488c2ecf20Sopenharmony_ci	.label = "sys_mci",
498c2ecf20Sopenharmony_ci	.base = -1,
508c2ecf20Sopenharmony_ci	.ngpio = 2,
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic struct bgpio_pdata vexpress_sysreg_sys_flash_pdata = {
548c2ecf20Sopenharmony_ci	.label = "sys_flash",
558c2ecf20Sopenharmony_ci	.base = -1,
568c2ecf20Sopenharmony_ci	.ngpio = 1,
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic struct mfd_cell vexpress_sysreg_cells[] = {
608c2ecf20Sopenharmony_ci	{
618c2ecf20Sopenharmony_ci		.name = "basic-mmio-gpio",
628c2ecf20Sopenharmony_ci		.of_compatible = "arm,vexpress-sysreg,sys_led",
638c2ecf20Sopenharmony_ci		.num_resources = 1,
648c2ecf20Sopenharmony_ci		.resources = (struct resource []) {
658c2ecf20Sopenharmony_ci			DEFINE_RES_MEM_NAMED(SYS_LED, 0x4, "dat"),
668c2ecf20Sopenharmony_ci		},
678c2ecf20Sopenharmony_ci		.platform_data = &vexpress_sysreg_sys_led_pdata,
688c2ecf20Sopenharmony_ci		.pdata_size = sizeof(vexpress_sysreg_sys_led_pdata),
698c2ecf20Sopenharmony_ci	}, {
708c2ecf20Sopenharmony_ci		.name = "basic-mmio-gpio",
718c2ecf20Sopenharmony_ci		.of_compatible = "arm,vexpress-sysreg,sys_mci",
728c2ecf20Sopenharmony_ci		.num_resources = 1,
738c2ecf20Sopenharmony_ci		.resources = (struct resource []) {
748c2ecf20Sopenharmony_ci			DEFINE_RES_MEM_NAMED(SYS_MCI, 0x4, "dat"),
758c2ecf20Sopenharmony_ci		},
768c2ecf20Sopenharmony_ci		.platform_data = &vexpress_sysreg_sys_mci_pdata,
778c2ecf20Sopenharmony_ci		.pdata_size = sizeof(vexpress_sysreg_sys_mci_pdata),
788c2ecf20Sopenharmony_ci	}, {
798c2ecf20Sopenharmony_ci		.name = "basic-mmio-gpio",
808c2ecf20Sopenharmony_ci		.of_compatible = "arm,vexpress-sysreg,sys_flash",
818c2ecf20Sopenharmony_ci		.num_resources = 1,
828c2ecf20Sopenharmony_ci		.resources = (struct resource []) {
838c2ecf20Sopenharmony_ci			DEFINE_RES_MEM_NAMED(SYS_FLASH, 0x4, "dat"),
848c2ecf20Sopenharmony_ci		},
858c2ecf20Sopenharmony_ci		.platform_data = &vexpress_sysreg_sys_flash_pdata,
868c2ecf20Sopenharmony_ci		.pdata_size = sizeof(vexpress_sysreg_sys_flash_pdata),
878c2ecf20Sopenharmony_ci	}, {
888c2ecf20Sopenharmony_ci		.name = "vexpress-syscfg",
898c2ecf20Sopenharmony_ci		.num_resources = 1,
908c2ecf20Sopenharmony_ci		.resources = (struct resource []) {
918c2ecf20Sopenharmony_ci			DEFINE_RES_MEM(SYS_MISC, 0x4c),
928c2ecf20Sopenharmony_ci		},
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int vexpress_sysreg_probe(struct platform_device *pdev)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct resource *mem;
998c2ecf20Sopenharmony_ci	void __iomem *base;
1008c2ecf20Sopenharmony_ci	struct gpio_chip *mmc_gpio_chip;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1038c2ecf20Sopenharmony_ci	if (!mem)
1048c2ecf20Sopenharmony_ci		return -EINVAL;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
1078c2ecf20Sopenharmony_ci	if (!base)
1088c2ecf20Sopenharmony_ci		return -ENOMEM;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	/*
1118c2ecf20Sopenharmony_ci	 * Duplicated SYS_MCI pseudo-GPIO controller for compatibility with
1128c2ecf20Sopenharmony_ci	 * older trees using sysreg node for MMC control lines.
1138c2ecf20Sopenharmony_ci	 */
1148c2ecf20Sopenharmony_ci	mmc_gpio_chip = devm_kzalloc(&pdev->dev, sizeof(*mmc_gpio_chip),
1158c2ecf20Sopenharmony_ci			GFP_KERNEL);
1168c2ecf20Sopenharmony_ci	if (!mmc_gpio_chip)
1178c2ecf20Sopenharmony_ci		return -ENOMEM;
1188c2ecf20Sopenharmony_ci	bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
1198c2ecf20Sopenharmony_ci			NULL, NULL, NULL, NULL, 0);
1208c2ecf20Sopenharmony_ci	mmc_gpio_chip->ngpio = 2;
1218c2ecf20Sopenharmony_ci	devm_gpiochip_add_data(&pdev->dev, mmc_gpio_chip, NULL);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
1248c2ecf20Sopenharmony_ci			vexpress_sysreg_cells,
1258c2ecf20Sopenharmony_ci			ARRAY_SIZE(vexpress_sysreg_cells), mem, 0, NULL);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic const struct of_device_id vexpress_sysreg_match[] = {
1298c2ecf20Sopenharmony_ci	{ .compatible = "arm,vexpress-sysreg", },
1308c2ecf20Sopenharmony_ci	{},
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, vexpress_sysreg_match);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic struct platform_driver vexpress_sysreg_driver = {
1358c2ecf20Sopenharmony_ci	.driver = {
1368c2ecf20Sopenharmony_ci		.name = "vexpress-sysreg",
1378c2ecf20Sopenharmony_ci		.of_match_table = vexpress_sysreg_match,
1388c2ecf20Sopenharmony_ci	},
1398c2ecf20Sopenharmony_ci	.probe = vexpress_sysreg_probe,
1408c2ecf20Sopenharmony_ci};
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cimodule_platform_driver(vexpress_sysreg_driver);
1438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
144