xref: /linux/drivers/soc/cirrus/soc-ep93xx.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * SoC driver for Cirrus EP93xx chips.
4  * Copyright (C) 2022 Nikita Shubin <nikita.shubin@maquefel.me>
5  *
6  * Based on a rewrite of arch/arm/mach-ep93xx/core.c
7  * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
8  * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
9  *
10  * Thanks go to Michael Burian and Ray Lehtiniemi for their key
11  * role in the ep93xx Linux community.
12  */
13 
14 #include <linux/bits.h>
15 #include <linux/cleanup.h>
16 #include <linux/init.h>
17 #include <linux/mfd/syscon.h>
18 #include <linux/of.h>
19 #include <linux/of_fdt.h>
20 #include <linux/platform_device.h>
21 #include <linux/regmap.h>
22 #include <linux/slab.h>
23 #include <linux/spinlock.h>
24 #include <linux/sys_soc.h>
25 
26 #include <linux/soc/cirrus/ep93xx.h>
27 
28 #define EP93XX_SYSCON_DEVCFG		0x80
29 
30 #define EP93XX_SWLOCK_MAGICK		0xaa
31 #define EP93XX_SYSCON_SWLOCK		0xc0
32 #define EP93XX_SYSCON_SYSCFG		0x9c
33 #define EP93XX_SYSCON_SYSCFG_REV_MASK	GENMASK(31, 28)
34 #define EP93XX_SYSCON_SYSCFG_REV_SHIFT	28
35 
36 struct ep93xx_map_info {
37 	spinlock_t lock;
38 	void __iomem *base;
39 	struct regmap *map;
40 };
41 
42 /*
43  * EP93xx System Controller software locked register write
44  *
45  * Logic safeguards are included to condition the control signals for
46  * power connection to the matrix to prevent part damage. In addition, a
47  * software lock register is included that must be written with 0xAA
48  * before each register write to change the values of the four switch
49  * matrix control registers.
50  */
51 static void ep93xx_regmap_write(struct regmap *map, spinlock_t *lock,
52 				 unsigned int reg, unsigned int val)
53 {
54 	guard(spinlock_irqsave)(lock);
55 
56 	regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
57 	regmap_write(map, reg, val);
58 }
59 
60 static void ep93xx_regmap_update_bits(struct regmap *map, spinlock_t *lock,
61 				      unsigned int reg, unsigned int mask,
62 				      unsigned int val)
63 {
64 	guard(spinlock_irqsave)(lock);
65 
66 	regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
67 	/* force write is required to clear swlock if no changes are made */
68 	regmap_update_bits_base(map, reg, mask, val, NULL, false, true);
69 }
70 
71 static void ep93xx_unregister_adev(void *_adev)
72 {
73 	struct auxiliary_device *adev = _adev;
74 
75 	auxiliary_device_delete(adev);
76 	auxiliary_device_uninit(adev);
77 }
78 
79 static void ep93xx_adev_release(struct device *dev)
80 {
81 	struct auxiliary_device *adev = to_auxiliary_dev(dev);
82 	struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev);
83 
84 	kfree(rdev);
85 }
86 
87 static struct auxiliary_device __init *ep93xx_adev_alloc(struct device *parent,
88 							 const char *name,
89 							 struct ep93xx_map_info *info)
90 {
91 	struct ep93xx_regmap_adev *rdev __free(kfree) = NULL;
92 	struct auxiliary_device *adev;
93 	int ret;
94 
95 	rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
96 	if (!rdev)
97 		return ERR_PTR(-ENOMEM);
98 
99 	rdev->map = info->map;
100 	rdev->base = info->base;
101 	rdev->lock = &info->lock;
102 	rdev->write = ep93xx_regmap_write;
103 	rdev->update_bits = ep93xx_regmap_update_bits;
104 
105 	adev = &rdev->adev;
106 	adev->name = name;
107 	adev->dev.parent = parent;
108 	adev->dev.release = ep93xx_adev_release;
109 
110 	ret = auxiliary_device_init(adev);
111 	if (ret)
112 		return ERR_PTR(ret);
113 
114 	return &no_free_ptr(rdev)->adev;
115 }
116 
117 static int __init ep93xx_controller_register(struct device *parent, const char *name,
118 					     struct ep93xx_map_info *info)
119 {
120 	struct auxiliary_device *adev;
121 	int ret;
122 
123 	adev = ep93xx_adev_alloc(parent, name, info);
124 	if (IS_ERR(adev))
125 		return PTR_ERR(adev);
126 
127 	ret = auxiliary_device_add(adev);
128 	if (ret) {
129 		auxiliary_device_uninit(adev);
130 		return ret;
131 	}
132 
133 	return devm_add_action_or_reset(parent, ep93xx_unregister_adev, adev);
134 }
135 
136 static unsigned int __init ep93xx_soc_revision(struct regmap *map)
137 {
138 	unsigned int val;
139 
140 	regmap_read(map, EP93XX_SYSCON_SYSCFG, &val);
141 	val &= EP93XX_SYSCON_SYSCFG_REV_MASK;
142 	val >>= EP93XX_SYSCON_SYSCFG_REV_SHIFT;
143 	return val;
144 }
145 
146 static const char __init *ep93xx_get_soc_rev(unsigned int rev)
147 {
148 	switch (rev) {
149 	case EP93XX_CHIP_REV_D0:
150 		return "D0";
151 	case EP93XX_CHIP_REV_D1:
152 		return "D1";
153 	case EP93XX_CHIP_REV_E0:
154 		return "E0";
155 	case EP93XX_CHIP_REV_E1:
156 		return "E1";
157 	case EP93XX_CHIP_REV_E2:
158 		return "E2";
159 	default:
160 		return "unknown";
161 	}
162 }
163 
164 static const char *pinctrl_names[] __initconst = {
165 	"pinctrl-ep9301",	/* EP93XX_9301_SOC */
166 	"pinctrl-ep9307",	/* EP93XX_9307_SOC */
167 	"pinctrl-ep9312",	/* EP93XX_9312_SOC */
168 };
169 
170 static int __init ep93xx_syscon_probe(struct platform_device *pdev)
171 {
172 	enum ep93xx_soc_model model;
173 	struct ep93xx_map_info *map_info;
174 	struct soc_device_attribute *attrs;
175 	struct soc_device *soc_dev;
176 	struct device *dev = &pdev->dev;
177 	struct regmap *map;
178 	void __iomem *base;
179 	unsigned int rev;
180 	int ret;
181 
182 	model = (enum ep93xx_soc_model)(uintptr_t)device_get_match_data(dev);
183 
184 	map = device_node_to_regmap(dev->of_node);
185 	if (IS_ERR(map))
186 		return PTR_ERR(map);
187 
188 	base = devm_platform_ioremap_resource(pdev, 0);
189 	if (IS_ERR(base))
190 		return PTR_ERR(base);
191 
192 	attrs = devm_kzalloc(dev, sizeof(*attrs), GFP_KERNEL);
193 	if (!attrs)
194 		return -ENOMEM;
195 
196 	rev = ep93xx_soc_revision(map);
197 
198 	attrs->machine = of_flat_dt_get_machine_name();
199 	attrs->family = "Cirrus Logic EP93xx";
200 	attrs->revision = ep93xx_get_soc_rev(rev);
201 
202 	soc_dev = soc_device_register(attrs);
203 	if (IS_ERR(soc_dev))
204 		return PTR_ERR(soc_dev);
205 
206 	map_info = devm_kzalloc(dev, sizeof(*map_info), GFP_KERNEL);
207 	if (!map_info)
208 		return -ENOMEM;
209 
210 	spin_lock_init(&map_info->lock);
211 	map_info->map = map;
212 	map_info->base = base;
213 
214 	ret = ep93xx_controller_register(dev, pinctrl_names[model], map_info);
215 	if (ret)
216 		dev_err(dev, "registering pinctrl controller failed\n");
217 
218 	/*
219 	 * EP93xx SSP clock rate was doubled in version E2. For more information
220 	 * see section 6 "2x SSP (Synchronous Serial Port) Clock – Revision E2 only":
221 	 *     http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
222 	 */
223 	if (rev == EP93XX_CHIP_REV_E2)
224 		ret = ep93xx_controller_register(dev, "clk-ep93xx.e2", map_info);
225 	else
226 		ret = ep93xx_controller_register(dev, "clk-ep93xx", map_info);
227 	if (ret)
228 		dev_err(dev, "registering clock controller failed\n");
229 
230 	ret = ep93xx_controller_register(dev, "reset-ep93xx", map_info);
231 	if (ret)
232 		dev_err(dev, "registering reset controller failed\n");
233 
234 	return 0;
235 }
236 
237 static const struct of_device_id ep9301_syscon_of_device_ids[] = {
238 	{ .compatible	= "cirrus,ep9301-syscon", .data = (void *)EP93XX_9301_SOC },
239 	{ .compatible	= "cirrus,ep9302-syscon", .data = (void *)EP93XX_9301_SOC },
240 	{ .compatible	= "cirrus,ep9307-syscon", .data = (void *)EP93XX_9307_SOC },
241 	{ .compatible	= "cirrus,ep9312-syscon", .data = (void *)EP93XX_9312_SOC },
242 	{ .compatible	= "cirrus,ep9315-syscon", .data = (void *)EP93XX_9312_SOC },
243 	{ /* sentinel */ }
244 };
245 
246 static struct platform_driver ep9301_syscon_driver = {
247 	.driver = {
248 		.name = "ep9301-syscon",
249 		.of_match_table = ep9301_syscon_of_device_ids,
250 	},
251 };
252 builtin_platform_driver_probe(ep9301_syscon_driver, ep93xx_syscon_probe);
253