From: Conor Dooley <conor.dooley@xxxxxxxxxxxxx> While the auxiliary bus was a nice bandaid, and meant that re-writing the representation of the clock regions in devicetree was not required, it has run its course. The "mss_top_sysreg" region that contains the clock and reset regions, also contains pinctrl and an interrupt controller, so the time has come rewrite the devicetree and probe the reset controller from a dedicated devicetree node, rather than implement those drivers using the auxiliary bus. Wanting to avoid propagating this naive/incorrect description of the hardware to the new pic64gx SoC is a major motivating factor here. Signed-off-by: Conor Dooley <conor.dooley@xxxxxxxxxxxxx> --- drivers/reset/reset-mpfs.c | 86 +++++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 11 deletions(-) diff --git a/drivers/reset/reset-mpfs.c b/drivers/reset/reset-mpfs.c index 710f9c1676f9..3b5c1f680e79 100644 --- a/drivers/reset/reset-mpfs.c +++ b/drivers/reset/reset-mpfs.c @@ -9,10 +9,12 @@ #include <linux/auxiliary_bus.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/regmap.h> #include <linux/reset-controller.h> #include <dt-bindings/clock/microchip,mpfs-clock.h> #include <soc/microchip/mpfs.h> @@ -27,11 +29,14 @@ #define MPFS_SLEEP_MIN_US 100 #define MPFS_SLEEP_MAX_US 200 +#define REG_SUBBLK_RESET_CR 0x88u + /* block concurrent access to the soft reset register */ static DEFINE_SPINLOCK(mpfs_reset_lock); struct mpfs_reset { void __iomem *base; + struct regmap *regmap; struct reset_controller_dev rcdev; }; @@ -51,9 +56,17 @@ static int mpfs_assert(struct reset_controller_dev *rcdev, unsigned long id) spin_lock_irqsave(&mpfs_reset_lock, flags); - reg = readl(rst->base); + if (rst->regmap) + regmap_read(rst->regmap, REG_SUBBLK_RESET_CR, ®); + else + reg = readl(rst->base); + reg |= BIT(id); - writel(reg, rst->base); + + if (rst->regmap) + regmap_write(rst->regmap, REG_SUBBLK_RESET_CR, reg); + else + writel(reg, rst->base); spin_unlock_irqrestore(&mpfs_reset_lock, flags); @@ -68,9 +81,17 @@ static int mpfs_deassert(struct reset_controller_dev *rcdev, unsigned long id) spin_lock_irqsave(&mpfs_reset_lock, flags); - reg = readl(rst->base); + if (rst->regmap) + regmap_read(rst->regmap, REG_SUBBLK_RESET_CR, ®); + else + reg = readl(rst->base); + reg &= ~BIT(id); - writel(reg, rst->base); + + if (rst->regmap) + regmap_write(rst->regmap, REG_SUBBLK_RESET_CR, reg); + else + writel(reg, rst->base); spin_unlock_irqrestore(&mpfs_reset_lock, flags); @@ -130,11 +151,54 @@ static int mpfs_reset_xlate(struct reset_controller_dev *rcdev, return index - MPFS_PERIPH_OFFSET; } -static int mpfs_reset_probe(struct auxiliary_device *adev, - const struct auxiliary_device_id *id) +static int mpfs_reset_of_probe(struct platform_device *pdev) { - struct device *dev = &adev->dev; struct reset_controller_dev *rcdev; + struct device *dev = &pdev->dev; + struct mpfs_reset *rst; + + rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL); + if (!rst) + return -ENOMEM; + + rst->regmap = syscon_node_to_regmap(dev->of_node->parent); + if (IS_ERR(rst->regmap)) + dev_err_probe(dev, PTR_ERR(rst->regmap), "Failed to find syscon regmap\n"); + + rcdev = &rst->rcdev; + rcdev->dev = dev; + rcdev->ops = &mpfs_reset_ops; + + rcdev->of_node = dev->of_node; + rcdev->of_reset_n_cells = 1; + rcdev->of_xlate = mpfs_reset_xlate; + rcdev->nr_resets = MPFS_NUM_RESETS; + + printk("of probe\n"); + + return devm_reset_controller_register(dev, rcdev); +} + +static const struct of_device_id mpfs_reset_of_match[] = { + { .compatible = "microchip,mpfs-reset", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mpfs_reset_of_match); + +static struct platform_driver mpfs_reset_of_driver = { + .probe = mpfs_reset_of_probe, + .driver = { + .name = "mpfs-reset", + .of_match_table = mpfs_reset_of_match, + }, +}; +module_platform_driver(mpfs_reset_of_driver); + +static int mpfs_reset_adev_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct reset_controller_dev *rcdev; + struct device *dev = &adev->dev; struct mpfs_reset *rst; rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL); @@ -145,8 +209,8 @@ static int mpfs_reset_probe(struct auxiliary_device *adev, rcdev = &rst->rcdev; rcdev->dev = dev; - rcdev->dev->parent = dev->parent; rcdev->ops = &mpfs_reset_ops; + rcdev->of_node = dev->parent->of_node; rcdev->of_reset_n_cells = 1; rcdev->of_xlate = mpfs_reset_xlate; @@ -222,12 +286,12 @@ static const struct auxiliary_device_id mpfs_reset_ids[] = { }; MODULE_DEVICE_TABLE(auxiliary, mpfs_reset_ids); -static struct auxiliary_driver mpfs_reset_driver = { - .probe = mpfs_reset_probe, +static struct auxiliary_driver mpfs_reset_aux_driver = { + .probe = mpfs_reset_adev_probe, .id_table = mpfs_reset_ids, }; -module_auxiliary_driver(mpfs_reset_driver); +module_auxiliary_driver(mpfs_reset_aux_driver); MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver"); MODULE_AUTHOR("Conor Dooley <conor.dooley@xxxxxxxxxxxxx>"); -- 2.43.0