253 lines · c
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.c7 * 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 key11 * 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 0x8029 30#define EP93XX_SWLOCK_MAGICK 0xaa31#define EP93XX_SYSCON_SWLOCK 0xc032#define EP93XX_SYSCON_SYSCFG 0x9c33#define EP93XX_SYSCON_SYSCFG_REV_MASK GENMASK(31, 28)34#define EP93XX_SYSCON_SYSCFG_REV_SHIFT 2835 36struct 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 write44 *45 * Logic safeguards are included to condition the control signals for46 * power connection to the matrix to prevent part damage. In addition, a47 * software lock register is included that must be written with 0xAA48 * before each register write to change the values of the four switch49 * matrix control registers.50 */51static 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 60static 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 71static 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 79static 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 87static 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 117static 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 136static 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 146static 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 164static 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 170static 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 information220 * see section 6 "2x SSP (Synchronous Serial Port) Clock – Revision E2 only":221 * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf222 */223 if (rev == EP93XX_CHIP_REV_E2)224 ret = ep93xx_controller_register(dev, "clk-ep93xx.e2", map_info);225 else226 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 237static 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 246static struct platform_driver ep9301_syscon_driver = {247 .driver = {248 .name = "ep9301-syscon",249 .of_match_table = ep9301_syscon_of_device_ids,250 },251};252builtin_platform_driver_probe(ep9301_syscon_driver, ep93xx_syscon_probe);253