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> 2181c22ad0SPhilipp Zabel #include <linux/spinlock.h> 2281c22ad0SPhilipp Zabel 2381c22ad0SPhilipp Zabel #include "reset-simple.h" 2481c22ad0SPhilipp Zabel 2581c22ad0SPhilipp Zabel static inline struct reset_simple_data * 2681c22ad0SPhilipp Zabel to_reset_simple_data(struct reset_controller_dev *rcdev) 2781c22ad0SPhilipp Zabel { 2881c22ad0SPhilipp Zabel return container_of(rcdev, struct reset_simple_data, rcdev); 2981c22ad0SPhilipp Zabel } 3081c22ad0SPhilipp Zabel 3181c22ad0SPhilipp Zabel static int reset_simple_update(struct reset_controller_dev *rcdev, 3281c22ad0SPhilipp Zabel unsigned long id, bool assert) 3381c22ad0SPhilipp Zabel { 3481c22ad0SPhilipp Zabel struct reset_simple_data *data = to_reset_simple_data(rcdev); 3581c22ad0SPhilipp Zabel int reg_width = sizeof(u32); 3681c22ad0SPhilipp Zabel int bank = id / (reg_width * BITS_PER_BYTE); 3781c22ad0SPhilipp Zabel int offset = id % (reg_width * BITS_PER_BYTE); 3881c22ad0SPhilipp Zabel unsigned long flags; 3981c22ad0SPhilipp Zabel u32 reg; 4081c22ad0SPhilipp Zabel 4181c22ad0SPhilipp Zabel spin_lock_irqsave(&data->lock, flags); 4281c22ad0SPhilipp Zabel 4381c22ad0SPhilipp Zabel reg = readl(data->membase + (bank * reg_width)); 4481c22ad0SPhilipp Zabel if (assert ^ data->active_low) 4581c22ad0SPhilipp Zabel reg |= BIT(offset); 4681c22ad0SPhilipp Zabel else 4781c22ad0SPhilipp Zabel reg &= ~BIT(offset); 4881c22ad0SPhilipp Zabel writel(reg, data->membase + (bank * reg_width)); 4981c22ad0SPhilipp Zabel 5081c22ad0SPhilipp Zabel spin_unlock_irqrestore(&data->lock, flags); 5181c22ad0SPhilipp Zabel 5281c22ad0SPhilipp Zabel return 0; 5381c22ad0SPhilipp Zabel } 5481c22ad0SPhilipp Zabel 5581c22ad0SPhilipp Zabel static int reset_simple_assert(struct reset_controller_dev *rcdev, 5681c22ad0SPhilipp Zabel unsigned long id) 5781c22ad0SPhilipp Zabel { 5881c22ad0SPhilipp Zabel return reset_simple_update(rcdev, id, true); 5981c22ad0SPhilipp Zabel } 6081c22ad0SPhilipp Zabel 6181c22ad0SPhilipp Zabel static int reset_simple_deassert(struct reset_controller_dev *rcdev, 6281c22ad0SPhilipp Zabel unsigned long id) 6381c22ad0SPhilipp Zabel { 6481c22ad0SPhilipp Zabel return reset_simple_update(rcdev, id, false); 6581c22ad0SPhilipp Zabel } 6681c22ad0SPhilipp Zabel 67adf20d7cSPhilipp Zabel static int reset_simple_status(struct reset_controller_dev *rcdev, 68adf20d7cSPhilipp Zabel unsigned long id) 69adf20d7cSPhilipp Zabel { 70adf20d7cSPhilipp Zabel struct reset_simple_data *data = to_reset_simple_data(rcdev); 71adf20d7cSPhilipp Zabel int reg_width = sizeof(u32); 72adf20d7cSPhilipp Zabel int bank = id / (reg_width * BITS_PER_BYTE); 73adf20d7cSPhilipp Zabel int offset = id % (reg_width * BITS_PER_BYTE); 74adf20d7cSPhilipp Zabel u32 reg; 75adf20d7cSPhilipp Zabel 76adf20d7cSPhilipp Zabel reg = readl(data->membase + (bank * reg_width)); 77adf20d7cSPhilipp Zabel 78adf20d7cSPhilipp Zabel return !(reg & BIT(offset)) ^ !data->status_active_low; 79adf20d7cSPhilipp Zabel } 80adf20d7cSPhilipp Zabel 8181c22ad0SPhilipp Zabel const struct reset_control_ops reset_simple_ops = { 8281c22ad0SPhilipp Zabel .assert = reset_simple_assert, 8381c22ad0SPhilipp Zabel .deassert = reset_simple_deassert, 84adf20d7cSPhilipp Zabel .status = reset_simple_status, 8581c22ad0SPhilipp Zabel }; 869ad39ab2SKunihiko Hayashi EXPORT_SYMBOL_GPL(reset_simple_ops); 8781c22ad0SPhilipp Zabel 8881c22ad0SPhilipp Zabel /** 8981c22ad0SPhilipp Zabel * struct reset_simple_devdata - simple reset controller properties 90adf20d7cSPhilipp Zabel * @reg_offset: offset between base address and first reset register. 91adf20d7cSPhilipp Zabel * @nr_resets: number of resets. If not set, default to resource size in bits. 9281c22ad0SPhilipp Zabel * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits 9381c22ad0SPhilipp Zabel * are set to assert the reset. 94adf20d7cSPhilipp Zabel * @status_active_low: if true, bits read back as cleared while the reset is 95adf20d7cSPhilipp Zabel * asserted. Otherwise, bits read back as set while the 96adf20d7cSPhilipp Zabel * reset is asserted. 9781c22ad0SPhilipp Zabel */ 9881c22ad0SPhilipp Zabel struct reset_simple_devdata { 99adf20d7cSPhilipp Zabel u32 reg_offset; 100adf20d7cSPhilipp Zabel u32 nr_resets; 10181c22ad0SPhilipp Zabel bool active_low; 102adf20d7cSPhilipp Zabel bool status_active_low; 103adf20d7cSPhilipp Zabel }; 104adf20d7cSPhilipp Zabel 105adf20d7cSPhilipp Zabel #define SOCFPGA_NR_BANKS 8 106adf20d7cSPhilipp Zabel 107adf20d7cSPhilipp Zabel static const struct reset_simple_devdata reset_simple_socfpga = { 108b3ca9888SDinh Nguyen .reg_offset = 0x20, 109adf20d7cSPhilipp Zabel .nr_resets = SOCFPGA_NR_BANKS * 32, 110adf20d7cSPhilipp Zabel .status_active_low = true, 11181c22ad0SPhilipp Zabel }; 11281c22ad0SPhilipp Zabel 11381c22ad0SPhilipp Zabel static const struct reset_simple_devdata reset_simple_active_low = { 11481c22ad0SPhilipp Zabel .active_low = true, 115adf20d7cSPhilipp Zabel .status_active_low = true, 11681c22ad0SPhilipp Zabel }; 11781c22ad0SPhilipp Zabel 11881c22ad0SPhilipp Zabel static const struct of_device_id reset_simple_dt_ids[] = { 119b3ca9888SDinh Nguyen { .compatible = "altr,stratix10-rst-mgr", 120b3ca9888SDinh Nguyen .data = &reset_simple_socfpga }, 1210af8a137SPhilipp Zabel { .compatible = "st,stm32-rcc", }, 12281c22ad0SPhilipp Zabel { .compatible = "allwinner,sun6i-a31-clock-reset", 12381c22ad0SPhilipp Zabel .data = &reset_simple_active_low }, 124f0e0ada6SPhilipp Zabel { .compatible = "zte,zx296718-reset", 125f0e0ada6SPhilipp Zabel .data = &reset_simple_active_low }, 1261d7592f8SJoel Stanley { .compatible = "aspeed,ast2400-lpc-reset" }, 1271d7592f8SJoel Stanley { .compatible = "aspeed,ast2500-lpc-reset" }, 12864c47b62SManivannan Sadhasivam { .compatible = "bitmain,bm1880-reset", 12964c47b62SManivannan Sadhasivam .data = &reset_simple_active_low }, 130*ea651ffdSGustavo Pimentel { .compatible = "snps,dw-high-reset" }, 131*ea651ffdSGustavo Pimentel { .compatible = "snps,dw-low-reset", 132*ea651ffdSGustavo Pimentel .data = &reset_simple_active_low }, 13381c22ad0SPhilipp Zabel { /* sentinel */ }, 13481c22ad0SPhilipp Zabel }; 13581c22ad0SPhilipp Zabel 13681c22ad0SPhilipp Zabel static int reset_simple_probe(struct platform_device *pdev) 13781c22ad0SPhilipp Zabel { 13881c22ad0SPhilipp Zabel struct device *dev = &pdev->dev; 13981c22ad0SPhilipp Zabel const struct reset_simple_devdata *devdata; 14081c22ad0SPhilipp Zabel struct reset_simple_data *data; 14181c22ad0SPhilipp Zabel void __iomem *membase; 14281c22ad0SPhilipp Zabel struct resource *res; 143adf20d7cSPhilipp Zabel u32 reg_offset = 0; 14481c22ad0SPhilipp Zabel 14581c22ad0SPhilipp Zabel devdata = of_device_get_match_data(dev); 14681c22ad0SPhilipp Zabel 14781c22ad0SPhilipp Zabel data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 14881c22ad0SPhilipp Zabel if (!data) 14981c22ad0SPhilipp Zabel return -ENOMEM; 15081c22ad0SPhilipp Zabel 15181c22ad0SPhilipp Zabel res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 15281c22ad0SPhilipp Zabel membase = devm_ioremap_resource(dev, res); 15381c22ad0SPhilipp Zabel if (IS_ERR(membase)) 15481c22ad0SPhilipp Zabel return PTR_ERR(membase); 15581c22ad0SPhilipp Zabel 15681c22ad0SPhilipp Zabel spin_lock_init(&data->lock); 15781c22ad0SPhilipp Zabel data->membase = membase; 15881c22ad0SPhilipp Zabel data->rcdev.owner = THIS_MODULE; 15981c22ad0SPhilipp Zabel data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; 16081c22ad0SPhilipp Zabel data->rcdev.ops = &reset_simple_ops; 16181c22ad0SPhilipp Zabel data->rcdev.of_node = dev->of_node; 16281c22ad0SPhilipp Zabel 163adf20d7cSPhilipp Zabel if (devdata) { 164adf20d7cSPhilipp Zabel reg_offset = devdata->reg_offset; 165adf20d7cSPhilipp Zabel if (devdata->nr_resets) 166adf20d7cSPhilipp Zabel data->rcdev.nr_resets = devdata->nr_resets; 16781c22ad0SPhilipp Zabel data->active_low = devdata->active_low; 168adf20d7cSPhilipp Zabel data->status_active_low = devdata->status_active_low; 169adf20d7cSPhilipp Zabel } 170adf20d7cSPhilipp Zabel 171adf20d7cSPhilipp Zabel data->membase += reg_offset; 17281c22ad0SPhilipp Zabel 17381c22ad0SPhilipp Zabel return devm_reset_controller_register(dev, &data->rcdev); 17481c22ad0SPhilipp Zabel } 17581c22ad0SPhilipp Zabel 17681c22ad0SPhilipp Zabel static struct platform_driver reset_simple_driver = { 17781c22ad0SPhilipp Zabel .probe = reset_simple_probe, 17881c22ad0SPhilipp Zabel .driver = { 17981c22ad0SPhilipp Zabel .name = "simple-reset", 18081c22ad0SPhilipp Zabel .of_match_table = reset_simple_dt_ids, 18181c22ad0SPhilipp Zabel }, 18281c22ad0SPhilipp Zabel }; 18381c22ad0SPhilipp Zabel builtin_platform_driver(reset_simple_driver); 184