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