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 1481c22ad0SPhilipp Zabel #include <linux/device.h> 1581c22ad0SPhilipp Zabel #include <linux/err.h> 1681c22ad0SPhilipp Zabel #include <linux/io.h> 1781c22ad0SPhilipp Zabel #include <linux/of.h> 1881c22ad0SPhilipp Zabel #include <linux/of_device.h> 1981c22ad0SPhilipp Zabel #include <linux/platform_device.h> 2081c22ad0SPhilipp Zabel #include <linux/reset-controller.h> 21*9357b046SMaxime 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 66adf20d7cSPhilipp Zabel static int reset_simple_status(struct reset_controller_dev *rcdev, 67adf20d7cSPhilipp Zabel unsigned long id) 68adf20d7cSPhilipp Zabel { 69adf20d7cSPhilipp Zabel struct reset_simple_data *data = to_reset_simple_data(rcdev); 70adf20d7cSPhilipp Zabel int reg_width = sizeof(u32); 71adf20d7cSPhilipp Zabel int bank = id / (reg_width * BITS_PER_BYTE); 72adf20d7cSPhilipp Zabel int offset = id % (reg_width * BITS_PER_BYTE); 73adf20d7cSPhilipp Zabel u32 reg; 74adf20d7cSPhilipp Zabel 75adf20d7cSPhilipp Zabel reg = readl(data->membase + (bank * reg_width)); 76adf20d7cSPhilipp Zabel 77adf20d7cSPhilipp Zabel return !(reg & BIT(offset)) ^ !data->status_active_low; 78adf20d7cSPhilipp Zabel } 79adf20d7cSPhilipp Zabel 8081c22ad0SPhilipp Zabel const struct reset_control_ops reset_simple_ops = { 8181c22ad0SPhilipp Zabel .assert = reset_simple_assert, 8281c22ad0SPhilipp Zabel .deassert = reset_simple_deassert, 83adf20d7cSPhilipp Zabel .status = reset_simple_status, 8481c22ad0SPhilipp Zabel }; 859ad39ab2SKunihiko Hayashi EXPORT_SYMBOL_GPL(reset_simple_ops); 8681c22ad0SPhilipp Zabel 8781c22ad0SPhilipp Zabel /** 8881c22ad0SPhilipp Zabel * struct reset_simple_devdata - simple reset controller properties 89adf20d7cSPhilipp Zabel * @reg_offset: offset between base address and first reset register. 90adf20d7cSPhilipp Zabel * @nr_resets: number of resets. If not set, default to resource size in bits. 9181c22ad0SPhilipp Zabel * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits 9281c22ad0SPhilipp Zabel * are set to assert the reset. 93adf20d7cSPhilipp Zabel * @status_active_low: if true, bits read back as cleared while the reset is 94adf20d7cSPhilipp Zabel * asserted. Otherwise, bits read back as set while the 95adf20d7cSPhilipp Zabel * reset is asserted. 9681c22ad0SPhilipp Zabel */ 9781c22ad0SPhilipp Zabel struct reset_simple_devdata { 98adf20d7cSPhilipp Zabel u32 reg_offset; 99adf20d7cSPhilipp Zabel u32 nr_resets; 10081c22ad0SPhilipp Zabel bool active_low; 101adf20d7cSPhilipp Zabel bool status_active_low; 102adf20d7cSPhilipp Zabel }; 103adf20d7cSPhilipp Zabel 104adf20d7cSPhilipp Zabel #define SOCFPGA_NR_BANKS 8 105adf20d7cSPhilipp Zabel 106adf20d7cSPhilipp Zabel static const struct reset_simple_devdata reset_simple_socfpga = { 107b3ca9888SDinh Nguyen .reg_offset = 0x20, 108adf20d7cSPhilipp Zabel .nr_resets = SOCFPGA_NR_BANKS * 32, 109adf20d7cSPhilipp Zabel .status_active_low = true, 11081c22ad0SPhilipp Zabel }; 11181c22ad0SPhilipp Zabel 11281c22ad0SPhilipp Zabel static const struct reset_simple_devdata reset_simple_active_low = { 11381c22ad0SPhilipp Zabel .active_low = true, 114adf20d7cSPhilipp Zabel .status_active_low = true, 11581c22ad0SPhilipp Zabel }; 11681c22ad0SPhilipp Zabel 11781c22ad0SPhilipp Zabel static const struct of_device_id reset_simple_dt_ids[] = { 118b3ca9888SDinh Nguyen { .compatible = "altr,stratix10-rst-mgr", 119b3ca9888SDinh Nguyen .data = &reset_simple_socfpga }, 1200af8a137SPhilipp Zabel { .compatible = "st,stm32-rcc", }, 12181c22ad0SPhilipp Zabel { .compatible = "allwinner,sun6i-a31-clock-reset", 12281c22ad0SPhilipp Zabel .data = &reset_simple_active_low }, 123f0e0ada6SPhilipp Zabel { .compatible = "zte,zx296718-reset", 124f0e0ada6SPhilipp Zabel .data = &reset_simple_active_low }, 1251d7592f8SJoel Stanley { .compatible = "aspeed,ast2400-lpc-reset" }, 1261d7592f8SJoel Stanley { .compatible = "aspeed,ast2500-lpc-reset" }, 12764c47b62SManivannan Sadhasivam { .compatible = "bitmain,bm1880-reset", 12864c47b62SManivannan Sadhasivam .data = &reset_simple_active_low }, 129ea651ffdSGustavo Pimentel { .compatible = "snps,dw-high-reset" }, 130ea651ffdSGustavo Pimentel { .compatible = "snps,dw-low-reset", 131ea651ffdSGustavo Pimentel .data = &reset_simple_active_low }, 13281c22ad0SPhilipp Zabel { /* sentinel */ }, 13381c22ad0SPhilipp Zabel }; 13481c22ad0SPhilipp Zabel 13581c22ad0SPhilipp Zabel static int reset_simple_probe(struct platform_device *pdev) 13681c22ad0SPhilipp Zabel { 13781c22ad0SPhilipp Zabel struct device *dev = &pdev->dev; 13881c22ad0SPhilipp Zabel const struct reset_simple_devdata *devdata; 13981c22ad0SPhilipp Zabel struct reset_simple_data *data; 14081c22ad0SPhilipp Zabel void __iomem *membase; 14181c22ad0SPhilipp Zabel struct resource *res; 142adf20d7cSPhilipp Zabel u32 reg_offset = 0; 14381c22ad0SPhilipp Zabel 14481c22ad0SPhilipp Zabel devdata = of_device_get_match_data(dev); 14581c22ad0SPhilipp Zabel 14681c22ad0SPhilipp Zabel data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 14781c22ad0SPhilipp Zabel if (!data) 14881c22ad0SPhilipp Zabel return -ENOMEM; 14981c22ad0SPhilipp Zabel 15081c22ad0SPhilipp Zabel res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 15181c22ad0SPhilipp Zabel membase = devm_ioremap_resource(dev, res); 15281c22ad0SPhilipp Zabel if (IS_ERR(membase)) 15381c22ad0SPhilipp Zabel return PTR_ERR(membase); 15481c22ad0SPhilipp Zabel 15581c22ad0SPhilipp Zabel spin_lock_init(&data->lock); 15681c22ad0SPhilipp Zabel data->membase = membase; 15781c22ad0SPhilipp Zabel data->rcdev.owner = THIS_MODULE; 15881c22ad0SPhilipp Zabel data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; 15981c22ad0SPhilipp Zabel data->rcdev.ops = &reset_simple_ops; 16081c22ad0SPhilipp Zabel data->rcdev.of_node = dev->of_node; 16181c22ad0SPhilipp Zabel 162adf20d7cSPhilipp Zabel if (devdata) { 163adf20d7cSPhilipp Zabel reg_offset = devdata->reg_offset; 164adf20d7cSPhilipp Zabel if (devdata->nr_resets) 165adf20d7cSPhilipp Zabel data->rcdev.nr_resets = devdata->nr_resets; 16681c22ad0SPhilipp Zabel data->active_low = devdata->active_low; 167adf20d7cSPhilipp Zabel data->status_active_low = devdata->status_active_low; 168adf20d7cSPhilipp Zabel } 169adf20d7cSPhilipp Zabel 170adf20d7cSPhilipp Zabel data->membase += reg_offset; 17181c22ad0SPhilipp Zabel 17281c22ad0SPhilipp Zabel return devm_reset_controller_register(dev, &data->rcdev); 17381c22ad0SPhilipp Zabel } 17481c22ad0SPhilipp Zabel 17581c22ad0SPhilipp Zabel static struct platform_driver reset_simple_driver = { 17681c22ad0SPhilipp Zabel .probe = reset_simple_probe, 17781c22ad0SPhilipp Zabel .driver = { 17881c22ad0SPhilipp Zabel .name = "simple-reset", 17981c22ad0SPhilipp Zabel .of_match_table = reset_simple_dt_ids, 18081c22ad0SPhilipp Zabel }, 18181c22ad0SPhilipp Zabel }; 18281c22ad0SPhilipp Zabel builtin_platform_driver(reset_simple_driver); 183