12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 281c22ad0SPhilipp Zabel /* 381c22ad0SPhilipp Zabel * Simple Reset Controller Driver 481c22ad0SPhilipp Zabel * 581c22ad0SPhilipp Zabel * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de> 681c22ad0SPhilipp Zabel * 781c22ad0SPhilipp Zabel * Based on Allwinner SoCs Reset Controller driver 881c22ad0SPhilipp Zabel * 981c22ad0SPhilipp Zabel * Copyright 2013 Maxime Ripard 1081c22ad0SPhilipp Zabel * 1181c22ad0SPhilipp Zabel * Maxime Ripard <maxime.ripard@free-electrons.com> 1281c22ad0SPhilipp Zabel */ 1381c22ad0SPhilipp Zabel 14a9701376SMaxime Ripard #include <linux/delay.h> 1581c22ad0SPhilipp Zabel #include <linux/device.h> 1681c22ad0SPhilipp Zabel #include <linux/err.h> 1781c22ad0SPhilipp Zabel #include <linux/io.h> 1881c22ad0SPhilipp Zabel #include <linux/of.h> 1981c22ad0SPhilipp Zabel #include <linux/platform_device.h> 2081c22ad0SPhilipp Zabel #include <linux/reset-controller.h> 219357b046SMaxime Ripard #include <linux/reset/reset-simple.h> 2281c22ad0SPhilipp Zabel #include <linux/spinlock.h> 2381c22ad0SPhilipp Zabel 2481c22ad0SPhilipp Zabel static inline struct reset_simple_data * 2581c22ad0SPhilipp Zabel to_reset_simple_data(struct reset_controller_dev *rcdev) 2681c22ad0SPhilipp Zabel { 2781c22ad0SPhilipp Zabel return container_of(rcdev, struct reset_simple_data, rcdev); 2881c22ad0SPhilipp Zabel } 2981c22ad0SPhilipp Zabel 3081c22ad0SPhilipp Zabel static int reset_simple_update(struct reset_controller_dev *rcdev, 3181c22ad0SPhilipp Zabel unsigned long id, bool assert) 3281c22ad0SPhilipp Zabel { 3381c22ad0SPhilipp Zabel struct reset_simple_data *data = to_reset_simple_data(rcdev); 3481c22ad0SPhilipp Zabel int reg_width = sizeof(u32); 3581c22ad0SPhilipp Zabel int bank = id / (reg_width * BITS_PER_BYTE); 3681c22ad0SPhilipp Zabel int offset = id % (reg_width * BITS_PER_BYTE); 3781c22ad0SPhilipp Zabel unsigned long flags; 3881c22ad0SPhilipp Zabel u32 reg; 3981c22ad0SPhilipp Zabel 4081c22ad0SPhilipp Zabel spin_lock_irqsave(&data->lock, flags); 4181c22ad0SPhilipp Zabel 4281c22ad0SPhilipp Zabel reg = readl(data->membase + (bank * reg_width)); 4381c22ad0SPhilipp Zabel if (assert ^ data->active_low) 4481c22ad0SPhilipp Zabel reg |= BIT(offset); 4581c22ad0SPhilipp Zabel else 4681c22ad0SPhilipp Zabel reg &= ~BIT(offset); 4781c22ad0SPhilipp Zabel writel(reg, data->membase + (bank * reg_width)); 4881c22ad0SPhilipp Zabel 4981c22ad0SPhilipp Zabel spin_unlock_irqrestore(&data->lock, flags); 5081c22ad0SPhilipp Zabel 5181c22ad0SPhilipp Zabel return 0; 5281c22ad0SPhilipp Zabel } 5381c22ad0SPhilipp Zabel 5481c22ad0SPhilipp Zabel static int reset_simple_assert(struct reset_controller_dev *rcdev, 5581c22ad0SPhilipp Zabel unsigned long id) 5681c22ad0SPhilipp Zabel { 5781c22ad0SPhilipp Zabel return reset_simple_update(rcdev, id, true); 5881c22ad0SPhilipp Zabel } 5981c22ad0SPhilipp Zabel 6081c22ad0SPhilipp Zabel static int reset_simple_deassert(struct reset_controller_dev *rcdev, 6181c22ad0SPhilipp Zabel unsigned long id) 6281c22ad0SPhilipp Zabel { 6381c22ad0SPhilipp Zabel return reset_simple_update(rcdev, id, false); 6481c22ad0SPhilipp Zabel } 6581c22ad0SPhilipp Zabel 66a9701376SMaxime Ripard static int reset_simple_reset(struct reset_controller_dev *rcdev, 67a9701376SMaxime Ripard unsigned long id) 68a9701376SMaxime Ripard { 69a9701376SMaxime Ripard struct reset_simple_data *data = to_reset_simple_data(rcdev); 70a9701376SMaxime Ripard int ret; 71a9701376SMaxime Ripard 72a9701376SMaxime Ripard if (!data->reset_us) 73a9701376SMaxime Ripard return -ENOTSUPP; 74a9701376SMaxime Ripard 75a9701376SMaxime Ripard ret = reset_simple_assert(rcdev, id); 76a9701376SMaxime Ripard if (ret) 77a9701376SMaxime Ripard return ret; 78a9701376SMaxime Ripard 79a9701376SMaxime Ripard usleep_range(data->reset_us, data->reset_us * 2); 80a9701376SMaxime Ripard 81a9701376SMaxime Ripard return reset_simple_deassert(rcdev, id); 82a9701376SMaxime Ripard } 83a9701376SMaxime Ripard 84adf20d7cSPhilipp Zabel static int reset_simple_status(struct reset_controller_dev *rcdev, 85adf20d7cSPhilipp Zabel unsigned long id) 86adf20d7cSPhilipp Zabel { 87adf20d7cSPhilipp Zabel struct reset_simple_data *data = to_reset_simple_data(rcdev); 88adf20d7cSPhilipp Zabel int reg_width = sizeof(u32); 89adf20d7cSPhilipp Zabel int bank = id / (reg_width * BITS_PER_BYTE); 90adf20d7cSPhilipp Zabel int offset = id % (reg_width * BITS_PER_BYTE); 91adf20d7cSPhilipp Zabel u32 reg; 92adf20d7cSPhilipp Zabel 93adf20d7cSPhilipp Zabel reg = readl(data->membase + (bank * reg_width)); 94adf20d7cSPhilipp Zabel 95adf20d7cSPhilipp Zabel return !(reg & BIT(offset)) ^ !data->status_active_low; 96adf20d7cSPhilipp Zabel } 97adf20d7cSPhilipp Zabel 9881c22ad0SPhilipp Zabel const struct reset_control_ops reset_simple_ops = { 9981c22ad0SPhilipp Zabel .assert = reset_simple_assert, 10081c22ad0SPhilipp Zabel .deassert = reset_simple_deassert, 101a9701376SMaxime Ripard .reset = reset_simple_reset, 102adf20d7cSPhilipp Zabel .status = reset_simple_status, 10381c22ad0SPhilipp Zabel }; 1049ad39ab2SKunihiko Hayashi EXPORT_SYMBOL_GPL(reset_simple_ops); 10581c22ad0SPhilipp Zabel 10681c22ad0SPhilipp Zabel /** 10781c22ad0SPhilipp Zabel * struct reset_simple_devdata - simple reset controller properties 108adf20d7cSPhilipp Zabel * @reg_offset: offset between base address and first reset register. 109adf20d7cSPhilipp Zabel * @nr_resets: number of resets. If not set, default to resource size in bits. 11081c22ad0SPhilipp Zabel * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits 11181c22ad0SPhilipp Zabel * are set to assert the reset. 112adf20d7cSPhilipp Zabel * @status_active_low: if true, bits read back as cleared while the reset is 113adf20d7cSPhilipp Zabel * asserted. Otherwise, bits read back as set while the 114adf20d7cSPhilipp Zabel * reset is asserted. 11581c22ad0SPhilipp Zabel */ 11681c22ad0SPhilipp Zabel struct reset_simple_devdata { 117adf20d7cSPhilipp Zabel u32 reg_offset; 118adf20d7cSPhilipp Zabel u32 nr_resets; 11981c22ad0SPhilipp Zabel bool active_low; 120adf20d7cSPhilipp Zabel bool status_active_low; 121adf20d7cSPhilipp Zabel }; 122adf20d7cSPhilipp Zabel 123adf20d7cSPhilipp Zabel #define SOCFPGA_NR_BANKS 8 124adf20d7cSPhilipp Zabel 125adf20d7cSPhilipp Zabel static const struct reset_simple_devdata reset_simple_socfpga = { 126b3ca9888SDinh Nguyen .reg_offset = 0x20, 127adf20d7cSPhilipp Zabel .nr_resets = SOCFPGA_NR_BANKS * 32, 128adf20d7cSPhilipp Zabel .status_active_low = true, 12981c22ad0SPhilipp Zabel }; 13081c22ad0SPhilipp Zabel 13181c22ad0SPhilipp Zabel static const struct reset_simple_devdata reset_simple_active_low = { 13281c22ad0SPhilipp Zabel .active_low = true, 133adf20d7cSPhilipp Zabel .status_active_low = true, 13481c22ad0SPhilipp Zabel }; 13581c22ad0SPhilipp Zabel 13681c22ad0SPhilipp Zabel static const struct of_device_id reset_simple_dt_ids[] = { 137b3ca9888SDinh Nguyen { .compatible = "altr,stratix10-rst-mgr", 138b3ca9888SDinh Nguyen .data = &reset_simple_socfpga }, 1390af8a137SPhilipp Zabel { .compatible = "st,stm32-rcc", }, 14081c22ad0SPhilipp Zabel { .compatible = "allwinner,sun6i-a31-clock-reset", 14181c22ad0SPhilipp Zabel .data = &reset_simple_active_low }, 142f0e0ada6SPhilipp Zabel { .compatible = "zte,zx296718-reset", 143f0e0ada6SPhilipp Zabel .data = &reset_simple_active_low }, 1441d7592f8SJoel Stanley { .compatible = "aspeed,ast2400-lpc-reset" }, 1451d7592f8SJoel Stanley { .compatible = "aspeed,ast2500-lpc-reset" }, 14677fb4e45SJoel Stanley { .compatible = "aspeed,ast2600-lpc-reset" }, 14764c47b62SManivannan Sadhasivam { .compatible = "bitmain,bm1880-reset", 14864c47b62SManivannan Sadhasivam .data = &reset_simple_active_low }, 149def26913SRafał Miłecki { .compatible = "brcm,bcm4908-misc-pcie-reset", 150def26913SRafał Miłecki .data = &reset_simple_active_low }, 151ea651ffdSGustavo Pimentel { .compatible = "snps,dw-high-reset" }, 152ea651ffdSGustavo Pimentel { .compatible = "snps,dw-low-reset", 153ea651ffdSGustavo Pimentel .data = &reset_simple_active_low }, 154*a6166a4dSChen Wang { .compatible = "sophgo,sg2042-reset", 155*a6166a4dSChen Wang .data = &reset_simple_active_low }, 15681c22ad0SPhilipp Zabel { /* sentinel */ }, 15781c22ad0SPhilipp Zabel }; 15881c22ad0SPhilipp Zabel 15981c22ad0SPhilipp Zabel static int reset_simple_probe(struct platform_device *pdev) 16081c22ad0SPhilipp Zabel { 16181c22ad0SPhilipp Zabel struct device *dev = &pdev->dev; 16281c22ad0SPhilipp Zabel const struct reset_simple_devdata *devdata; 16381c22ad0SPhilipp Zabel struct reset_simple_data *data; 16481c22ad0SPhilipp Zabel void __iomem *membase; 16581c22ad0SPhilipp Zabel struct resource *res; 166adf20d7cSPhilipp Zabel u32 reg_offset = 0; 16781c22ad0SPhilipp Zabel 16881c22ad0SPhilipp Zabel devdata = of_device_get_match_data(dev); 16981c22ad0SPhilipp Zabel 17081c22ad0SPhilipp Zabel data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 17181c22ad0SPhilipp Zabel if (!data) 17281c22ad0SPhilipp Zabel return -ENOMEM; 17381c22ad0SPhilipp Zabel 174ac53e621SYangtao Li membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 17581c22ad0SPhilipp Zabel if (IS_ERR(membase)) 17681c22ad0SPhilipp Zabel return PTR_ERR(membase); 17781c22ad0SPhilipp Zabel 17881c22ad0SPhilipp Zabel spin_lock_init(&data->lock); 17981c22ad0SPhilipp Zabel data->membase = membase; 18081c22ad0SPhilipp Zabel data->rcdev.owner = THIS_MODULE; 18181c22ad0SPhilipp Zabel data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; 18281c22ad0SPhilipp Zabel data->rcdev.ops = &reset_simple_ops; 18381c22ad0SPhilipp Zabel data->rcdev.of_node = dev->of_node; 18481c22ad0SPhilipp Zabel 185adf20d7cSPhilipp Zabel if (devdata) { 186adf20d7cSPhilipp Zabel reg_offset = devdata->reg_offset; 187adf20d7cSPhilipp Zabel if (devdata->nr_resets) 188adf20d7cSPhilipp Zabel data->rcdev.nr_resets = devdata->nr_resets; 18981c22ad0SPhilipp Zabel data->active_low = devdata->active_low; 190adf20d7cSPhilipp Zabel data->status_active_low = devdata->status_active_low; 191adf20d7cSPhilipp Zabel } 192adf20d7cSPhilipp Zabel 193adf20d7cSPhilipp Zabel data->membase += reg_offset; 19481c22ad0SPhilipp Zabel 19581c22ad0SPhilipp Zabel return devm_reset_controller_register(dev, &data->rcdev); 19681c22ad0SPhilipp Zabel } 19781c22ad0SPhilipp Zabel 19881c22ad0SPhilipp Zabel static struct platform_driver reset_simple_driver = { 19981c22ad0SPhilipp Zabel .probe = reset_simple_probe, 20081c22ad0SPhilipp Zabel .driver = { 20181c22ad0SPhilipp Zabel .name = "simple-reset", 20281c22ad0SPhilipp Zabel .of_match_table = reset_simple_dt_ids, 20381c22ad0SPhilipp Zabel }, 20481c22ad0SPhilipp Zabel }; 20581c22ad0SPhilipp Zabel builtin_platform_driver(reset_simple_driver); 206