1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * |
4 | * Copyright (C) 2012 ARM Limited |
5 | */ |
6 | |
7 | #include <linux/gpio/driver.h> |
8 | #include <linux/err.h> |
9 | #include <linux/io.h> |
10 | #include <linux/mfd/core.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of_platform.h> |
13 | #include <linux/platform_data/syscon.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/stat.h> |
17 | |
18 | #define SYS_ID 0x000 |
19 | #define SYS_SW 0x004 |
20 | #define SYS_LED 0x008 |
21 | #define SYS_100HZ 0x024 |
22 | #define SYS_FLAGSSET 0x030 |
23 | #define SYS_FLAGSCLR 0x034 |
24 | #define SYS_NVFLAGS 0x038 |
25 | #define SYS_NVFLAGSSET 0x038 |
26 | #define SYS_NVFLAGSCLR 0x03c |
27 | #define SYS_MCI 0x048 |
28 | #define SYS_FLASH 0x04c |
29 | #define SYS_CFGSW 0x058 |
30 | #define SYS_24MHZ 0x05c |
31 | #define SYS_MISC 0x060 |
32 | #define SYS_DMA 0x064 |
33 | #define SYS_PROCID0 0x084 |
34 | #define SYS_PROCID1 0x088 |
35 | #define SYS_CFGDATA 0x0a0 |
36 | #define SYS_CFGCTRL 0x0a4 |
37 | #define SYS_CFGSTAT 0x0a8 |
38 | |
39 | /* The sysreg block is just a random collection of various functions... */ |
40 | |
41 | static struct bgpio_pdata vexpress_sysreg_sys_led_pdata = { |
42 | .label = "sys_led" , |
43 | .base = -1, |
44 | .ngpio = 8, |
45 | }; |
46 | |
47 | static struct bgpio_pdata vexpress_sysreg_sys_mci_pdata = { |
48 | .label = "sys_mci" , |
49 | .base = -1, |
50 | .ngpio = 2, |
51 | }; |
52 | |
53 | static struct bgpio_pdata vexpress_sysreg_sys_flash_pdata = { |
54 | .label = "sys_flash" , |
55 | .base = -1, |
56 | .ngpio = 1, |
57 | }; |
58 | |
59 | static struct mfd_cell vexpress_sysreg_cells[] = { |
60 | { |
61 | .name = "basic-mmio-gpio" , |
62 | .of_compatible = "arm,vexpress-sysreg,sys_led" , |
63 | .num_resources = 1, |
64 | .resources = &DEFINE_RES_MEM_NAMED(SYS_LED, 0x4, "dat" ), |
65 | .platform_data = &vexpress_sysreg_sys_led_pdata, |
66 | .pdata_size = sizeof(vexpress_sysreg_sys_led_pdata), |
67 | }, { |
68 | .name = "basic-mmio-gpio" , |
69 | .of_compatible = "arm,vexpress-sysreg,sys_mci" , |
70 | .num_resources = 1, |
71 | .resources = &DEFINE_RES_MEM_NAMED(SYS_MCI, 0x4, "dat" ), |
72 | .platform_data = &vexpress_sysreg_sys_mci_pdata, |
73 | .pdata_size = sizeof(vexpress_sysreg_sys_mci_pdata), |
74 | }, { |
75 | .name = "basic-mmio-gpio" , |
76 | .of_compatible = "arm,vexpress-sysreg,sys_flash" , |
77 | .num_resources = 1, |
78 | .resources = &DEFINE_RES_MEM_NAMED(SYS_FLASH, 0x4, "dat" ), |
79 | .platform_data = &vexpress_sysreg_sys_flash_pdata, |
80 | .pdata_size = sizeof(vexpress_sysreg_sys_flash_pdata), |
81 | }, { |
82 | .name = "vexpress-syscfg" , |
83 | .num_resources = 1, |
84 | .resources = &DEFINE_RES_MEM(SYS_MISC, 0x4c), |
85 | } |
86 | }; |
87 | |
88 | static int vexpress_sysreg_probe(struct platform_device *pdev) |
89 | { |
90 | struct resource *mem; |
91 | void __iomem *base; |
92 | struct gpio_chip *mmc_gpio_chip; |
93 | |
94 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
95 | if (!mem) |
96 | return -EINVAL; |
97 | |
98 | base = devm_ioremap(dev: &pdev->dev, offset: mem->start, size: resource_size(res: mem)); |
99 | if (!base) |
100 | return -ENOMEM; |
101 | |
102 | /* |
103 | * Duplicated SYS_MCI pseudo-GPIO controller for compatibility with |
104 | * older trees using sysreg node for MMC control lines. |
105 | */ |
106 | mmc_gpio_chip = devm_kzalloc(dev: &pdev->dev, size: sizeof(*mmc_gpio_chip), |
107 | GFP_KERNEL); |
108 | if (!mmc_gpio_chip) |
109 | return -ENOMEM; |
110 | bgpio_init(gc: mmc_gpio_chip, dev: &pdev->dev, sz: 0x4, dat: base + SYS_MCI, |
111 | NULL, NULL, NULL, NULL, flags: 0); |
112 | mmc_gpio_chip->ngpio = 2; |
113 | devm_gpiochip_add_data(&pdev->dev, mmc_gpio_chip, NULL); |
114 | |
115 | return devm_mfd_add_devices(dev: &pdev->dev, PLATFORM_DEVID_AUTO, |
116 | cells: vexpress_sysreg_cells, |
117 | ARRAY_SIZE(vexpress_sysreg_cells), mem_base: mem, irq_base: 0, NULL); |
118 | } |
119 | |
120 | static const struct of_device_id vexpress_sysreg_match[] = { |
121 | { .compatible = "arm,vexpress-sysreg" , }, |
122 | {}, |
123 | }; |
124 | MODULE_DEVICE_TABLE(of, vexpress_sysreg_match); |
125 | |
126 | static struct platform_driver vexpress_sysreg_driver = { |
127 | .driver = { |
128 | .name = "vexpress-sysreg" , |
129 | .of_match_table = vexpress_sysreg_match, |
130 | }, |
131 | .probe = vexpress_sysreg_probe, |
132 | }; |
133 | |
134 | module_platform_driver(vexpress_sysreg_driver); |
135 | MODULE_LICENSE("GPL v2" ); |
136 | |