181c22ad0SPhilipp Zabel /* 281c22ad0SPhilipp Zabel * Simple Reset Controller Driver 381c22ad0SPhilipp Zabel * 481c22ad0SPhilipp Zabel * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de> 581c22ad0SPhilipp Zabel * 681c22ad0SPhilipp Zabel * Based on Allwinner SoCs Reset Controller driver 781c22ad0SPhilipp Zabel * 881c22ad0SPhilipp Zabel * Copyright 2013 Maxime Ripard 981c22ad0SPhilipp Zabel * 1081c22ad0SPhilipp Zabel * Maxime Ripard <maxime.ripard@free-electrons.com> 1181c22ad0SPhilipp Zabel * 1281c22ad0SPhilipp Zabel * This program is free software; you can redistribute it and/or modify 1381c22ad0SPhilipp Zabel * it under the terms of the GNU General Public License as published by 1481c22ad0SPhilipp Zabel * the Free Software Foundation; either version 2 of the License, or 1581c22ad0SPhilipp Zabel * (at your option) any later version. 1681c22ad0SPhilipp Zabel */ 1781c22ad0SPhilipp Zabel 1881c22ad0SPhilipp Zabel #include <linux/device.h> 1981c22ad0SPhilipp Zabel #include <linux/err.h> 2081c22ad0SPhilipp Zabel #include <linux/io.h> 2181c22ad0SPhilipp Zabel #include <linux/of.h> 2281c22ad0SPhilipp Zabel #include <linux/of_device.h> 2381c22ad0SPhilipp Zabel #include <linux/platform_device.h> 2481c22ad0SPhilipp Zabel #include <linux/reset-controller.h> 2581c22ad0SPhilipp Zabel #include <linux/spinlock.h> 2681c22ad0SPhilipp Zabel 2781c22ad0SPhilipp Zabel #include "reset-simple.h" 2881c22ad0SPhilipp Zabel 2981c22ad0SPhilipp Zabel static inline struct reset_simple_data * 3081c22ad0SPhilipp Zabel to_reset_simple_data(struct reset_controller_dev *rcdev) 3181c22ad0SPhilipp Zabel { 3281c22ad0SPhilipp Zabel return container_of(rcdev, struct reset_simple_data, rcdev); 3381c22ad0SPhilipp Zabel } 3481c22ad0SPhilipp Zabel 3581c22ad0SPhilipp Zabel static int reset_simple_update(struct reset_controller_dev *rcdev, 3681c22ad0SPhilipp Zabel unsigned long id, bool assert) 3781c22ad0SPhilipp Zabel { 3881c22ad0SPhilipp Zabel struct reset_simple_data *data = to_reset_simple_data(rcdev); 3981c22ad0SPhilipp Zabel int reg_width = sizeof(u32); 4081c22ad0SPhilipp Zabel int bank = id / (reg_width * BITS_PER_BYTE); 4181c22ad0SPhilipp Zabel int offset = id % (reg_width * BITS_PER_BYTE); 4281c22ad0SPhilipp Zabel unsigned long flags; 4381c22ad0SPhilipp Zabel u32 reg; 4481c22ad0SPhilipp Zabel 4581c22ad0SPhilipp Zabel spin_lock_irqsave(&data->lock, flags); 4681c22ad0SPhilipp Zabel 4781c22ad0SPhilipp Zabel reg = readl(data->membase + (bank * reg_width)); 4881c22ad0SPhilipp Zabel if (assert ^ data->active_low) 4981c22ad0SPhilipp Zabel reg |= BIT(offset); 5081c22ad0SPhilipp Zabel else 5181c22ad0SPhilipp Zabel reg &= ~BIT(offset); 5281c22ad0SPhilipp Zabel writel(reg, data->membase + (bank * reg_width)); 5381c22ad0SPhilipp Zabel 5481c22ad0SPhilipp Zabel spin_unlock_irqrestore(&data->lock, flags); 5581c22ad0SPhilipp Zabel 5681c22ad0SPhilipp Zabel return 0; 5781c22ad0SPhilipp Zabel } 5881c22ad0SPhilipp Zabel 5981c22ad0SPhilipp Zabel static int reset_simple_assert(struct reset_controller_dev *rcdev, 6081c22ad0SPhilipp Zabel unsigned long id) 6181c22ad0SPhilipp Zabel { 6281c22ad0SPhilipp Zabel return reset_simple_update(rcdev, id, true); 6381c22ad0SPhilipp Zabel } 6481c22ad0SPhilipp Zabel 6581c22ad0SPhilipp Zabel static int reset_simple_deassert(struct reset_controller_dev *rcdev, 6681c22ad0SPhilipp Zabel unsigned long id) 6781c22ad0SPhilipp Zabel { 6881c22ad0SPhilipp Zabel return reset_simple_update(rcdev, id, false); 6981c22ad0SPhilipp Zabel } 7081c22ad0SPhilipp Zabel 71adf20d7cSPhilipp Zabel static int reset_simple_status(struct reset_controller_dev *rcdev, 72adf20d7cSPhilipp Zabel unsigned long id) 73adf20d7cSPhilipp Zabel { 74adf20d7cSPhilipp Zabel struct reset_simple_data *data = to_reset_simple_data(rcdev); 75adf20d7cSPhilipp Zabel int reg_width = sizeof(u32); 76adf20d7cSPhilipp Zabel int bank = id / (reg_width * BITS_PER_BYTE); 77adf20d7cSPhilipp Zabel int offset = id % (reg_width * BITS_PER_BYTE); 78adf20d7cSPhilipp Zabel u32 reg; 79adf20d7cSPhilipp Zabel 80adf20d7cSPhilipp Zabel reg = readl(data->membase + (bank * reg_width)); 81adf20d7cSPhilipp Zabel 82adf20d7cSPhilipp Zabel return !(reg & BIT(offset)) ^ !data->status_active_low; 83adf20d7cSPhilipp Zabel } 84adf20d7cSPhilipp Zabel 8581c22ad0SPhilipp Zabel const struct reset_control_ops reset_simple_ops = { 8681c22ad0SPhilipp Zabel .assert = reset_simple_assert, 8781c22ad0SPhilipp Zabel .deassert = reset_simple_deassert, 88adf20d7cSPhilipp Zabel .status = reset_simple_status, 8981c22ad0SPhilipp Zabel }; 909ad39ab2SKunihiko Hayashi EXPORT_SYMBOL_GPL(reset_simple_ops); 9181c22ad0SPhilipp Zabel 9281c22ad0SPhilipp Zabel /** 9381c22ad0SPhilipp Zabel * struct reset_simple_devdata - simple reset controller properties 94adf20d7cSPhilipp Zabel * @reg_offset: offset between base address and first reset register. 95adf20d7cSPhilipp Zabel * @nr_resets: number of resets. If not set, default to resource size in bits. 9681c22ad0SPhilipp Zabel * @active_low: if true, bits are cleared to assert the reset. Otherwise, bits 9781c22ad0SPhilipp Zabel * are set to assert the reset. 98adf20d7cSPhilipp Zabel * @status_active_low: if true, bits read back as cleared while the reset is 99adf20d7cSPhilipp Zabel * asserted. Otherwise, bits read back as set while the 100adf20d7cSPhilipp Zabel * reset is asserted. 10181c22ad0SPhilipp Zabel */ 10281c22ad0SPhilipp Zabel struct reset_simple_devdata { 103adf20d7cSPhilipp Zabel u32 reg_offset; 104adf20d7cSPhilipp Zabel u32 nr_resets; 10581c22ad0SPhilipp Zabel bool active_low; 106adf20d7cSPhilipp Zabel bool status_active_low; 107adf20d7cSPhilipp Zabel }; 108adf20d7cSPhilipp Zabel 109adf20d7cSPhilipp Zabel #define SOCFPGA_NR_BANKS 8 110adf20d7cSPhilipp Zabel 111adf20d7cSPhilipp Zabel static const struct reset_simple_devdata reset_simple_socfpga = { 112b3ca9888SDinh Nguyen .reg_offset = 0x20, 113adf20d7cSPhilipp Zabel .nr_resets = SOCFPGA_NR_BANKS * 32, 114adf20d7cSPhilipp Zabel .status_active_low = true, 11581c22ad0SPhilipp Zabel }; 11681c22ad0SPhilipp Zabel 11781c22ad0SPhilipp Zabel static const struct reset_simple_devdata reset_simple_active_low = { 11881c22ad0SPhilipp Zabel .active_low = true, 119adf20d7cSPhilipp Zabel .status_active_low = true, 12081c22ad0SPhilipp Zabel }; 12181c22ad0SPhilipp Zabel 12281c22ad0SPhilipp Zabel static const struct of_device_id reset_simple_dt_ids[] = { 123b3ca9888SDinh Nguyen { .compatible = "altr,stratix10-rst-mgr", 124b3ca9888SDinh Nguyen .data = &reset_simple_socfpga }, 1250af8a137SPhilipp Zabel { .compatible = "st,stm32-rcc", }, 12681c22ad0SPhilipp Zabel { .compatible = "allwinner,sun6i-a31-clock-reset", 12781c22ad0SPhilipp Zabel .data = &reset_simple_active_low }, 128f0e0ada6SPhilipp Zabel { .compatible = "zte,zx296718-reset", 129f0e0ada6SPhilipp Zabel .data = &reset_simple_active_low }, 1301d7592f8SJoel Stanley { .compatible = "aspeed,ast2400-lpc-reset" }, 1311d7592f8SJoel Stanley { .compatible = "aspeed,ast2500-lpc-reset" }, 132*64c47b62SManivannan Sadhasivam { .compatible = "bitmain,bm1880-reset", 133*64c47b62SManivannan Sadhasivam .data = &reset_simple_active_low }, 13481c22ad0SPhilipp Zabel { /* sentinel */ }, 13581c22ad0SPhilipp Zabel }; 13681c22ad0SPhilipp Zabel 13781c22ad0SPhilipp Zabel static int reset_simple_probe(struct platform_device *pdev) 13881c22ad0SPhilipp Zabel { 13981c22ad0SPhilipp Zabel struct device *dev = &pdev->dev; 14081c22ad0SPhilipp Zabel const struct reset_simple_devdata *devdata; 14181c22ad0SPhilipp Zabel struct reset_simple_data *data; 14281c22ad0SPhilipp Zabel void __iomem *membase; 14381c22ad0SPhilipp Zabel struct resource *res; 144adf20d7cSPhilipp Zabel u32 reg_offset = 0; 14581c22ad0SPhilipp Zabel 14681c22ad0SPhilipp Zabel devdata = of_device_get_match_data(dev); 14781c22ad0SPhilipp Zabel 14881c22ad0SPhilipp Zabel data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 14981c22ad0SPhilipp Zabel if (!data) 15081c22ad0SPhilipp Zabel return -ENOMEM; 15181c22ad0SPhilipp Zabel 15281c22ad0SPhilipp Zabel res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 15381c22ad0SPhilipp Zabel membase = devm_ioremap_resource(dev, res); 15481c22ad0SPhilipp Zabel if (IS_ERR(membase)) 15581c22ad0SPhilipp Zabel return PTR_ERR(membase); 15681c22ad0SPhilipp Zabel 15781c22ad0SPhilipp Zabel spin_lock_init(&data->lock); 15881c22ad0SPhilipp Zabel data->membase = membase; 15981c22ad0SPhilipp Zabel data->rcdev.owner = THIS_MODULE; 16081c22ad0SPhilipp Zabel data->rcdev.nr_resets = resource_size(res) * BITS_PER_BYTE; 16181c22ad0SPhilipp Zabel data->rcdev.ops = &reset_simple_ops; 16281c22ad0SPhilipp Zabel data->rcdev.of_node = dev->of_node; 16381c22ad0SPhilipp Zabel 164adf20d7cSPhilipp Zabel if (devdata) { 165adf20d7cSPhilipp Zabel reg_offset = devdata->reg_offset; 166adf20d7cSPhilipp Zabel if (devdata->nr_resets) 167adf20d7cSPhilipp Zabel data->rcdev.nr_resets = devdata->nr_resets; 16881c22ad0SPhilipp Zabel data->active_low = devdata->active_low; 169adf20d7cSPhilipp Zabel data->status_active_low = devdata->status_active_low; 170adf20d7cSPhilipp Zabel } 171adf20d7cSPhilipp Zabel 172adf20d7cSPhilipp Zabel data->membase += reg_offset; 17381c22ad0SPhilipp Zabel 17481c22ad0SPhilipp Zabel return devm_reset_controller_register(dev, &data->rcdev); 17581c22ad0SPhilipp Zabel } 17681c22ad0SPhilipp Zabel 17781c22ad0SPhilipp Zabel static struct platform_driver reset_simple_driver = { 17881c22ad0SPhilipp Zabel .probe = reset_simple_probe, 17981c22ad0SPhilipp Zabel .driver = { 18081c22ad0SPhilipp Zabel .name = "simple-reset", 18181c22ad0SPhilipp Zabel .of_match_table = reset_simple_dt_ids, 18281c22ad0SPhilipp Zabel }, 18381c22ad0SPhilipp Zabel }; 18481c22ad0SPhilipp Zabel builtin_platform_driver(reset_simple_driver); 185