Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

reset: add BCM6345 reset controller driver

Add support for resetting blocks through the Linux reset controller
subsystem for BCM63xx SoCs.

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
Reviewed-by: Florian Fainelli <F.fainelli@gmail.com>
Reviewed-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>

authored by

Álvaro Fernández Rojas and committed by
Thomas Bogendoerfer
aac02543 10c1e714

+143
+7
drivers/reset/Kconfig
··· 35 35 help 36 36 This enables the reset controller driver for AXS10x. 37 37 38 + config RESET_BCM6345 39 + bool "BCM6345 Reset Controller" 40 + depends on BMIPS_GENERIC || COMPILE_TEST 41 + default BMIPS_GENERIC 42 + help 43 + This enables the reset controller driver for BCM6345 SoCs. 44 + 38 45 config RESET_BERLIN 39 46 bool "Berlin Reset Driver" if COMPILE_TEST 40 47 default ARCH_BERLIN
+1
drivers/reset/Makefile
··· 6 6 obj-$(CONFIG_RESET_A10SR) += reset-a10sr.o 7 7 obj-$(CONFIG_RESET_ATH79) += reset-ath79.o 8 8 obj-$(CONFIG_RESET_AXS10X) += reset-axs10x.o 9 + obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o 9 10 obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o 10 11 obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o 11 12 obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o
+135
drivers/reset/reset-bcm6345.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * BCM6345 Reset Controller Driver 4 + * 5 + * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com> 6 + */ 7 + 8 + #include <linux/delay.h> 9 + #include <linux/init.h> 10 + #include <linux/io.h> 11 + #include <linux/mod_devicetable.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/reset-controller.h> 14 + 15 + #define BCM6345_RESET_NUM 32 16 + #define BCM6345_RESET_SLEEP_MIN_US 10000 17 + #define BCM6345_RESET_SLEEP_MAX_US 20000 18 + 19 + struct bcm6345_reset { 20 + struct reset_controller_dev rcdev; 21 + void __iomem *base; 22 + spinlock_t lock; 23 + }; 24 + 25 + static inline struct bcm6345_reset * 26 + to_bcm6345_reset(struct reset_controller_dev *rcdev) 27 + { 28 + return container_of(rcdev, struct bcm6345_reset, rcdev); 29 + } 30 + 31 + static int bcm6345_reset_update(struct reset_controller_dev *rcdev, 32 + unsigned long id, bool assert) 33 + { 34 + struct bcm6345_reset *bcm6345_reset = to_bcm6345_reset(rcdev); 35 + unsigned long flags; 36 + uint32_t val; 37 + 38 + spin_lock_irqsave(&bcm6345_reset->lock, flags); 39 + val = __raw_readl(bcm6345_reset->base); 40 + if (assert) 41 + val &= ~BIT(id); 42 + else 43 + val |= BIT(id); 44 + __raw_writel(val, bcm6345_reset->base); 45 + spin_unlock_irqrestore(&bcm6345_reset->lock, flags); 46 + 47 + return 0; 48 + } 49 + 50 + static int bcm6345_reset_assert(struct reset_controller_dev *rcdev, 51 + unsigned long id) 52 + { 53 + return bcm6345_reset_update(rcdev, id, true); 54 + } 55 + 56 + static int bcm6345_reset_deassert(struct reset_controller_dev *rcdev, 57 + unsigned long id) 58 + { 59 + return bcm6345_reset_update(rcdev, id, false); 60 + } 61 + 62 + static int bcm6345_reset_reset(struct reset_controller_dev *rcdev, 63 + unsigned long id) 64 + { 65 + bcm6345_reset_update(rcdev, id, true); 66 + usleep_range(BCM6345_RESET_SLEEP_MIN_US, 67 + BCM6345_RESET_SLEEP_MAX_US); 68 + 69 + bcm6345_reset_update(rcdev, id, false); 70 + /* 71 + * Ensure component is taken out reset state by sleeping also after 72 + * deasserting the reset. Otherwise, the component may not be ready 73 + * for operation. 74 + */ 75 + usleep_range(BCM6345_RESET_SLEEP_MIN_US, 76 + BCM6345_RESET_SLEEP_MAX_US); 77 + 78 + return 0; 79 + } 80 + 81 + static int bcm6345_reset_status(struct reset_controller_dev *rcdev, 82 + unsigned long id) 83 + { 84 + struct bcm6345_reset *bcm6345_reset = to_bcm6345_reset(rcdev); 85 + 86 + return !(__raw_readl(bcm6345_reset->base) & BIT(id)); 87 + } 88 + 89 + static struct reset_control_ops bcm6345_reset_ops = { 90 + .assert = bcm6345_reset_assert, 91 + .deassert = bcm6345_reset_deassert, 92 + .reset = bcm6345_reset_reset, 93 + .status = bcm6345_reset_status, 94 + }; 95 + 96 + static int bcm6345_reset_probe(struct platform_device *pdev) 97 + { 98 + struct bcm6345_reset *bcm6345_reset; 99 + 100 + bcm6345_reset = devm_kzalloc(&pdev->dev, 101 + sizeof(*bcm6345_reset), GFP_KERNEL); 102 + if (!bcm6345_reset) 103 + return -ENOMEM; 104 + 105 + platform_set_drvdata(pdev, bcm6345_reset); 106 + 107 + bcm6345_reset->base = devm_platform_ioremap_resource(pdev, 0); 108 + if (IS_ERR(bcm6345_reset->base)) 109 + return PTR_ERR(bcm6345_reset->base); 110 + 111 + spin_lock_init(&bcm6345_reset->lock); 112 + bcm6345_reset->rcdev.ops = &bcm6345_reset_ops; 113 + bcm6345_reset->rcdev.owner = THIS_MODULE; 114 + bcm6345_reset->rcdev.of_node = pdev->dev.of_node; 115 + bcm6345_reset->rcdev.of_reset_n_cells = 1; 116 + bcm6345_reset->rcdev.nr_resets = BCM6345_RESET_NUM; 117 + 118 + return devm_reset_controller_register(&pdev->dev, 119 + &bcm6345_reset->rcdev); 120 + } 121 + 122 + static const struct of_device_id bcm6345_reset_of_match[] = { 123 + { .compatible = "brcm,bcm6345-reset" }, 124 + { /* sentinel */ }, 125 + }; 126 + 127 + static struct platform_driver bcm6345_reset_driver = { 128 + .probe = bcm6345_reset_probe, 129 + .driver = { 130 + .name = "bcm6345-reset", 131 + .of_match_table = bcm6345_reset_of_match, 132 + .suppress_bind_attrs = true, 133 + }, 134 + }; 135 + builtin_platform_driver(bcm6345_reset_driver);