Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later 2 : : /* 3 : : * Simple Reset Controller Driver 4 : : * 5 : : * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de> 6 : : * 7 : : * Based on Allwinner SoCs Reset Controller driver 8 : : * 9 : : * Copyright 2013 Maxime Ripard 10 : : * 11 : : * Maxime Ripard <maxime.ripard@free-electrons.com> 12 : : */ 13 : : 14 : : #include <linux/delay.h> 15 : : #include <linux/device.h> 16 : : #include <linux/err.h> 17 : : #include <linux/io.h> 18 : : #include <linux/of.h> 19 : : #include <linux/of_device.h> 20 : : #include <linux/platform_device.h> 21 : : #include <linux/reset-controller.h> 22 : : #include <linux/reset/reset-simple.h> 23 : : #include <linux/spinlock.h> 24 : : 25 : : static inline struct reset_simple_data * 26 : : to_reset_simple_data(struct reset_controller_dev *rcdev) 27 : : { 28 : : return container_of(rcdev, struct reset_simple_data, rcdev); 29 : : } 30 : : 31 : 0 : static int reset_simple_update(struct reset_controller_dev *rcdev, 32 : : unsigned long id, bool assert) 33 : : { 34 : : struct reset_simple_data *data = to_reset_simple_data(rcdev); 35 : : int reg_width = sizeof(u32); 36 : 0 : int bank = id / (reg_width * BITS_PER_BYTE); 37 : 0 : int offset = id % (reg_width * BITS_PER_BYTE); 38 : : unsigned long flags; 39 : : u32 reg; 40 : : 41 : 0 : spin_lock_irqsave(&data->lock, flags); 42 : : 43 : 0 : reg = readl(data->membase + (bank * reg_width)); 44 : 0 : if (assert ^ data->active_low) 45 : 0 : reg |= BIT(offset); 46 : : else 47 : 0 : reg &= ~BIT(offset); 48 : 0 : writel(reg, data->membase + (bank * reg_width)); 49 : : 50 : : spin_unlock_irqrestore(&data->lock, flags); 51 : : 52 : 0 : return 0; 53 : : } 54 : : 55 : 0 : static int reset_simple_assert(struct reset_controller_dev *rcdev, 56 : : unsigned long id) 57 : : { 58 : 0 : return reset_simple_update(rcdev, id, true); 59 : : } 60 : : 61 : 0 : static int reset_simple_deassert(struct reset_controller_dev *rcdev, 62 : : unsigned long id) 63 : : { 64 : 0 : return reset_simple_update(rcdev, id, false); 65 : : } 66 : : 67 : 0 : static int reset_simple_reset(struct reset_controller_dev *rcdev, 68 : : unsigned long id) 69 : : { 70 : : struct reset_simple_data *data = to_reset_simple_data(rcdev); 71 : : int ret; 72 : : 73 : 0 : if (!data->reset_us) 74 : : return -ENOTSUPP; 75 : : 76 : : ret = reset_simple_assert(rcdev, id); 77 : 0 : if (ret) 78 : : return ret; 79 : : 80 : 0 : usleep_range(data->reset_us, data->reset_us * 2); 81 : : 82 : : ret = reset_simple_deassert(rcdev, id); 83 : 0 : if (ret) 84 : 0 : return ret; 85 : : 86 : : return 0; 87 : : } 88 : : 89 : 0 : static int reset_simple_status(struct reset_controller_dev *rcdev, 90 : : unsigned long id) 91 : : { 92 : : struct reset_simple_data *data = to_reset_simple_data(rcdev); 93 : : int reg_width = sizeof(u32); 94 : 0 : int bank = id / (reg_width * BITS_PER_BYTE); 95 : 0 : int offset = id % (reg_width * BITS_PER_BYTE); 96 : : u32 reg; 97 : : 98 : 0 : reg = readl(data->membase + (bank * reg_width)); 99 : : 100 : 0 : return !(reg & BIT(offset)) ^ !data->status_active_low; 101 : : } 102 : : 103 : : const struct reset_control_ops reset_simple_ops = { 104 : : .assert = reset_simple_assert, 105 : : .deassert = reset_simple_deassert, 106 : : .reset = reset_simple_reset, 107 : : .status = reset_simple_status, 108 : : }; 109 : : EXPORT_SYMBOL_GPL(reset_simple_ops); 110 : : 111 : : /** 112 : : * struct reset_simple_devdata - simple reset controller properties 113 : : * @reg_offset: offset between base address and first reset register. 114 : : * @nr_resets: number of resets. If not set, default to resource size in bits. 115 : : * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits 116 : : * are set to assert the reset. 117 : : * @status_active_low: if true, bits read back as cleared while the reset is 118 : : * asserted. Otherwise, bits read back as set while the 119 : : * reset is asserted. 120 : : */ 121 : : struct reset_simple_devdata { 122 : : u32 reg_offset; 123 : : u32 nr_resets; 124 : : bool active_low; 125 : : bool status_active_low; 126 : : }; 127 : : 128 : : #define SOCFPGA_NR_BANKS 8 129 : : 130 : : static const struct reset_simple_devdata reset_simple_socfpga = { 131 : : .reg_offset = 0x20, 132 : : .nr_resets = SOCFPGA_NR_BANKS * 32, 133 : : .status_active_low = true, 134 : : }; 135 : : 136 : : static const struct reset_simple_devdata reset_simple_active_low = { 137 : : .active_low = true, 138 : : .status_active_low = true, 139 : : }; 140 : : 141 : : static const struct of_device_id reset_simple_dt_ids[] = { 142 : : { .compatible = "altr,stratix10-rst-mgr", 143 : : .data = &reset_simple_socfpga }, 144 : : { .compatible = "st,stm32-rcc", }, 145 : : { .compatible = "allwinner,sun6i-a31-clock-reset", 146 : : .data = &reset_simple_active_low }, 147 : : { .compatible = "zte,zx296718-reset", 148 : : .data = &reset_simple_active_low }, 149 : : { .compatible = "aspeed,ast2400-lpc-reset" }, 150 : : { .compatible = "aspeed,ast2500-lpc-reset" }, 151 : : { .compatible = "bitmain,bm1880-reset", 152 : : .data = &reset_simple_active_low }, 153 : : { .compatible = "snps,dw-high-reset" }, 154 : : { .compatible = "snps,dw-low-reset", 155 : : .data = &reset_simple_active_low }, 156 : : { /* sentinel */ }, 157 : : }; 158 : : 159 : 0 : static int reset_simple_probe(struct platform_device *pdev) 160 : : { 161 : 0 : struct device *dev = &pdev->dev; 162 : : const struct reset_simple_devdata *devdata; 163 : : struct reset_simple_data *data; 164 : : void __iomem *membase; 165 : : struct resource *res; 166 : : u32 reg_offset = 0; 167 : : 168 : 0 : devdata = of_device_get_match_data(dev); 169 : : 170 : : data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 171 : 0 : if (!data) 172 : : return -ENOMEM; 173 : : 174 : 0 : res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 175 : 0 : membase = devm_ioremap_resource(dev, res); 176 : 0 : if (IS_ERR(membase)) 177 : 0 : return PTR_ERR(membase); 178 : : 179 : 0 : spin_lock_init(&data->lock); 180 : 0 : data->membase = membase; 181 : 0 : data->rcdev.owner = THIS_MODULE; 182 : 0 : data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; 183 : 0 : data->rcdev.ops = &reset_simple_ops; 184 : 0 : data->rcdev.of_node = dev->of_node; 185 : : 186 : 0 : if (devdata) { 187 : 0 : reg_offset = devdata->reg_offset; 188 : 0 : if (devdata->nr_resets) 189 : 0 : data->rcdev.nr_resets = devdata->nr_resets; 190 : 0 : data->active_low = devdata->active_low; 191 : 0 : data->status_active_low = devdata->status_active_low; 192 : : } 193 : : 194 : 0 : data->membase += reg_offset; 195 : : 196 : 0 : return devm_reset_controller_register(dev, &data->rcdev); 197 : : } 198 : : 199 : : static struct platform_driver reset_simple_driver = { 200 : : .probe = reset_simple_probe, 201 : : .driver = { 202 : : .name = "simple-reset", 203 : : .of_match_table = reset_simple_dt_ids, 204 : : }, 205 : : }; 206 : 3 : builtin_platform_driver(reset_simple_driver);