Merge branch 'drivers/reset' into next/late
* drivers/reset: reset: ath79: Fix missing spin_lock_init reset: Add (devm_)reset_control_get stub functions reset: reset-zynq: Adding support for Xilinx Zynq reset controller. docs: dts: Added documentation for Xilinx Zynq Reset Controller bindings. MIPS: ath79: Add the reset controller to the AR9132 dtsi reset: Add a driver for the reset controller on the AR71XX/AR9XXX devicetree: Add bindings for the ATH79 reset controller reset: socfpga: Update reset-socfpga to read the altr,modrst-offset property doc: dt: add documentation for lpc1850-rgu reset driver reset: add driver for lpc18xx rgu reset: sti: constify of_device_id array ARM: STi: DT: Move reset controller constants into common location MAINTAINERS: add include/dt-bindings/reset path to reset controller entry
This commit is contained in:
commit
71d440499b
|
@ -0,0 +1,20 @@
|
|||
Binding for Qualcomm Atheros AR7xxx/AR9XXX reset controller
|
||||
|
||||
Please also refer to reset.txt in this directory for common reset
|
||||
controller binding usage.
|
||||
|
||||
Required Properties:
|
||||
- compatible: has to be "qca,<soctype>-reset", "qca,ar7100-reset"
|
||||
as fallback
|
||||
- reg: Base address and size of the controllers memory area
|
||||
- #reset-cells : Specifies the number of cells needed to encode reset
|
||||
line, should be 1
|
||||
|
||||
Example:
|
||||
|
||||
reset-controller@1806001c {
|
||||
compatible = "qca,ar9132-reset", "qca,ar7100-reset";
|
||||
reg = <0x1806001c 0x4>;
|
||||
|
||||
#reset-cells = <1>;
|
||||
};
|
|
@ -0,0 +1,84 @@
|
|||
NXP LPC1850 Reset Generation Unit (RGU)
|
||||
========================================
|
||||
|
||||
Please also refer to reset.txt in this directory for common reset
|
||||
controller binding usage.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "nxp,lpc1850-rgu"
|
||||
- reg: register base and length
|
||||
- clocks: phandle and clock specifier to RGU clocks
|
||||
- clock-names: should contain "delay" and "reg"
|
||||
- #reset-cells: should be 1
|
||||
|
||||
See table below for valid peripheral reset numbers. Numbers not
|
||||
in the table below are either reserved or not applicable for
|
||||
normal operation.
|
||||
|
||||
Reset Peripheral
|
||||
9 System control unit (SCU)
|
||||
12 ARM Cortex-M0 subsystem core (LPC43xx only)
|
||||
13 CPU core
|
||||
16 LCD controller
|
||||
17 USB0
|
||||
18 USB1
|
||||
19 DMA
|
||||
20 SDIO
|
||||
21 External memory controller (EMC)
|
||||
22 Ethernet
|
||||
25 Flash bank A
|
||||
27 EEPROM
|
||||
28 GPIO
|
||||
29 Flash bank B
|
||||
32 Timer0
|
||||
33 Timer1
|
||||
34 Timer2
|
||||
35 Timer3
|
||||
36 Repetitive Interrupt timer (RIT)
|
||||
37 State Configurable Timer (SCT)
|
||||
38 Motor control PWM (MCPWM)
|
||||
39 QEI
|
||||
40 ADC0
|
||||
41 ADC1
|
||||
42 DAC
|
||||
44 USART0
|
||||
45 UART1
|
||||
46 USART2
|
||||
47 USART3
|
||||
48 I2C0
|
||||
49 I2C1
|
||||
50 SSP0
|
||||
51 SSP1
|
||||
52 I2S0 and I2S1
|
||||
53 Serial Flash Interface (SPIFI)
|
||||
54 C_CAN1
|
||||
55 C_CAN0
|
||||
56 ARM Cortex-M0 application core (LPC4370 only)
|
||||
57 SGPIO (LPC43xx only)
|
||||
58 SPI (LPC43xx only)
|
||||
60 ADCHS (12-bit ADC) (LPC4370 only)
|
||||
|
||||
Refer to NXP LPC18xx or LPC43xx user manual for more details about
|
||||
the reset signals and the connected block/peripheral.
|
||||
|
||||
Reset provider example:
|
||||
rgu: reset-controller@40053000 {
|
||||
compatible = "nxp,lpc1850-rgu";
|
||||
reg = <0x40053000 0x1000>;
|
||||
clocks = <&cgu BASE_SAFE_CLK>, <&ccu1 CLK_CPU_BUS>;
|
||||
clock-names = "delay", "reg";
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
Reset consumer example:
|
||||
mac: ethernet@40010000 {
|
||||
compatible = "nxp,lpc1850-dwmac", "snps,dwmac-3.611", "snps,dwmac";
|
||||
reg = <0x40010000 0x2000>;
|
||||
interrupts = <5>;
|
||||
interrupt-names = "macirq";
|
||||
clocks = <&ccu1 CLK_CPU_ETHERNET>;
|
||||
clock-names = "stmmaceth";
|
||||
resets = <&rgu 22>;
|
||||
reset-names = "stmmaceth";
|
||||
status = "disabled";
|
||||
};
|
|
@ -39,4 +39,4 @@ Example:
|
|||
};
|
||||
|
||||
Macro definitions for the supported reset channels can be found in:
|
||||
include/dt-bindings/reset-controller/stih407-resets.h
|
||||
include/dt-bindings/reset/stih407-resets.h
|
||||
|
|
|
@ -43,5 +43,5 @@ example:
|
|||
|
||||
Macro definitions for the supported reset channels can be found in:
|
||||
|
||||
include/dt-bindings/reset-controller/stih415-resets.h
|
||||
include/dt-bindings/reset-controller/stih416-resets.h
|
||||
include/dt-bindings/reset/stih415-resets.h
|
||||
include/dt-bindings/reset/stih416-resets.h
|
||||
|
|
|
@ -42,5 +42,5 @@ example:
|
|||
|
||||
Macro definitions for the supported reset channels can be found in:
|
||||
|
||||
include/dt-bindings/reset-controller/stih415-resets.h
|
||||
include/dt-bindings/reset-controller/stih416-resets.h
|
||||
include/dt-bindings/reset/stih415-resets.h
|
||||
include/dt-bindings/reset/stih416-resets.h
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
Xilinx Zynq Reset Manager
|
||||
|
||||
The Zynq AP-SoC has several different resets.
|
||||
|
||||
See Chapter 26 of the Zynq TRM (UG585) for more information about Zynq resets.
|
||||
|
||||
Required properties:
|
||||
- compatible: "xlnx,zynq-reset"
|
||||
- reg: SLCR offset and size taken via syscon <0x200 0x48>
|
||||
- syscon: <&slcr>
|
||||
This should be a phandle to the Zynq's SLCR registers.
|
||||
- #reset-cells: Must be 1
|
||||
|
||||
The Zynq Reset Manager needs to be a childnode of the SLCR.
|
||||
|
||||
Example:
|
||||
rstc: rstc@200 {
|
||||
compatible = "xlnx,zynq-reset";
|
||||
reg = <0x200 0x48>;
|
||||
#reset-cells = <1>;
|
||||
syscon = <&slcr>;
|
||||
};
|
||||
|
||||
Reset outputs:
|
||||
0 : soft reset
|
||||
32 : ddr reset
|
||||
64 : topsw reset
|
||||
96 : dmac reset
|
||||
128: usb0 reset
|
||||
129: usb1 reset
|
||||
160: gem0 reset
|
||||
161: gem1 reset
|
||||
164: gem0 rx reset
|
||||
165: gem1 rx reset
|
||||
166: gem0 ref reset
|
||||
167: gem1 ref reset
|
||||
192: sdio0 reset
|
||||
193: sdio1 reset
|
||||
196: sdio0 ref reset
|
||||
197: sdio1 ref reset
|
||||
224: spi0 reset
|
||||
225: spi1 reset
|
||||
226: spi0 ref reset
|
||||
227: spi1 ref reset
|
||||
256: can0 reset
|
||||
257: can1 reset
|
||||
258: can0 ref reset
|
||||
259: can1 ref reset
|
||||
288: i2c0 reset
|
||||
289: i2c1 reset
|
||||
320: uart0 reset
|
||||
321: uart1 reset
|
||||
322: uart0 ref reset
|
||||
323: uart1 ref reset
|
||||
352: gpio reset
|
||||
384: lqspi reset
|
||||
385: qspi ref reset
|
||||
416: smc reset
|
||||
417: smc ref reset
|
||||
448: ocm reset
|
||||
512: fpga0 out reset
|
||||
513: fpga1 out reset
|
||||
514: fpga2 out reset
|
||||
515: fpga3 out reset
|
||||
544: a9 reset 0
|
||||
545: a9 reset 1
|
||||
552: peri reset
|
||||
|
|
@ -8553,6 +8553,7 @@ M: Philipp Zabel <p.zabel@pengutronix.de>
|
|||
S: Maintained
|
||||
F: drivers/reset/
|
||||
F: Documentation/devicetree/bindings/reset/
|
||||
F: include/dt-bindings/reset/
|
||||
F: include/linux/reset.h
|
||||
F: include/linux/reset-controller.h
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "stih407-pinctrl.dtsi"
|
||||
#include <dt-bindings/mfd/st-lpc.h>
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include <dt-bindings/reset-controller/stih407-resets.h>
|
||||
#include <dt-bindings/reset/stih407-resets.h>
|
||||
#include <dt-bindings/interrupt-controller/irq-st.h>
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "stih415-clock.dtsi"
|
||||
#include "stih415-pinctrl.dtsi"
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/reset-controller/stih415-resets.h>
|
||||
#include <dt-bindings/reset/stih415-resets.h>
|
||||
/ {
|
||||
|
||||
L2: cache-controller {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/reset-controller/stih416-resets.h>
|
||||
#include <dt-bindings/reset/stih416-resets.h>
|
||||
#include <dt-bindings/interrupt-controller/irq-st.h>
|
||||
/ {
|
||||
L2: cache-controller {
|
||||
|
|
|
@ -118,6 +118,7 @@ config ATH25
|
|||
|
||||
config ATH79
|
||||
bool "Atheros AR71XX/AR724X/AR913X based boards"
|
||||
select ARCH_HAS_RESET_CONTROLLER
|
||||
select ARCH_REQUIRE_GPIOLIB
|
||||
select BOOT_RAW
|
||||
select CEVT_R4K
|
||||
|
|
|
@ -115,6 +115,14 @@
|
|||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
};
|
||||
|
||||
rst: reset-controller@1806001c {
|
||||
compatible = "qca,ar9132-reset",
|
||||
"qca,ar7100-reset";
|
||||
reg = <0x1806001c 0x4>;
|
||||
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
spi@1f000000 {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
obj-$(CONFIG_RESET_CONTROLLER) += core.o
|
||||
obj-$(CONFIG_ARCH_LPC18XX) += reset-lpc18xx.o
|
||||
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
|
||||
obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
|
||||
obj-$(CONFIG_ARCH_STI) += sti/
|
||||
obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o
|
||||
obj-$(CONFIG_ATH79) += reset-ath79.o
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Alban Bedel <albeu@free.fr>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
|
||||
struct ath79_reset {
|
||||
struct reset_controller_dev rcdev;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static int ath79_reset_update(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, bool assert)
|
||||
{
|
||||
struct ath79_reset *ath79_reset =
|
||||
container_of(rcdev, struct ath79_reset, rcdev);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&ath79_reset->lock, flags);
|
||||
val = readl(ath79_reset->base);
|
||||
if (assert)
|
||||
val |= BIT(id);
|
||||
else
|
||||
val &= ~BIT(id);
|
||||
writel(val, ath79_reset->base);
|
||||
spin_unlock_irqrestore(&ath79_reset->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath79_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return ath79_reset_update(rcdev, id, true);
|
||||
}
|
||||
|
||||
static int ath79_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return ath79_reset_update(rcdev, id, false);
|
||||
}
|
||||
|
||||
static int ath79_reset_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct ath79_reset *ath79_reset =
|
||||
container_of(rcdev, struct ath79_reset, rcdev);
|
||||
u32 val;
|
||||
|
||||
val = readl(ath79_reset->base);
|
||||
|
||||
return !!(val & BIT(id));
|
||||
}
|
||||
|
||||
static struct reset_control_ops ath79_reset_ops = {
|
||||
.assert = ath79_reset_assert,
|
||||
.deassert = ath79_reset_deassert,
|
||||
.status = ath79_reset_status,
|
||||
};
|
||||
|
||||
static int ath79_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ath79_reset *ath79_reset;
|
||||
struct resource *res;
|
||||
|
||||
ath79_reset = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*ath79_reset), GFP_KERNEL);
|
||||
if (!ath79_reset)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ath79_reset);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
ath79_reset->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(ath79_reset->base))
|
||||
return PTR_ERR(ath79_reset->base);
|
||||
|
||||
spin_lock_init(&ath79_reset->lock);
|
||||
ath79_reset->rcdev.ops = &ath79_reset_ops;
|
||||
ath79_reset->rcdev.owner = THIS_MODULE;
|
||||
ath79_reset->rcdev.of_node = pdev->dev.of_node;
|
||||
ath79_reset->rcdev.of_reset_n_cells = 1;
|
||||
ath79_reset->rcdev.nr_resets = 32;
|
||||
|
||||
return reset_controller_register(&ath79_reset->rcdev);
|
||||
}
|
||||
|
||||
static int ath79_reset_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ath79_reset *ath79_reset = platform_get_drvdata(pdev);
|
||||
|
||||
reset_controller_unregister(&ath79_reset->rcdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ath79_reset_dt_ids[] = {
|
||||
{ .compatible = "qca,ar7100-reset", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ath79_reset_dt_ids);
|
||||
|
||||
static struct platform_driver ath79_reset_driver = {
|
||||
.probe = ath79_reset_probe,
|
||||
.remove = ath79_reset_remove,
|
||||
.driver = {
|
||||
.name = "ath79-reset",
|
||||
.of_match_table = ath79_reset_dt_ids,
|
||||
},
|
||||
};
|
||||
module_platform_driver(ath79_reset_driver);
|
||||
|
||||
MODULE_AUTHOR("Alban Bedel <albeu@free.fr>");
|
||||
MODULE_DESCRIPTION("AR71xx Reset Controller Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,258 @@
|
|||
/*
|
||||
* Reset driver for NXP LPC18xx/43xx Reset Generation Unit (RGU).
|
||||
*
|
||||
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/* LPC18xx RGU registers */
|
||||
#define LPC18XX_RGU_CTRL0 0x100
|
||||
#define LPC18XX_RGU_CTRL1 0x104
|
||||
#define LPC18XX_RGU_ACTIVE_STATUS0 0x150
|
||||
#define LPC18XX_RGU_ACTIVE_STATUS1 0x154
|
||||
|
||||
#define LPC18XX_RGU_RESETS_PER_REG 32
|
||||
|
||||
/* Internal reset outputs */
|
||||
#define LPC18XX_RGU_CORE_RST 0
|
||||
#define LPC43XX_RGU_M0SUB_RST 12
|
||||
#define LPC43XX_RGU_M0APP_RST 56
|
||||
|
||||
struct lpc18xx_rgu_data {
|
||||
struct reset_controller_dev rcdev;
|
||||
struct clk *clk_delay;
|
||||
struct clk *clk_reg;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
u32 delay_us;
|
||||
};
|
||||
|
||||
#define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev)
|
||||
|
||||
static void __iomem *rgu_base;
|
||||
|
||||
static int lpc18xx_rgu_restart(struct notifier_block *this, unsigned long mode,
|
||||
void *cmd)
|
||||
{
|
||||
writel(BIT(LPC18XX_RGU_CORE_RST), rgu_base + LPC18XX_RGU_CTRL0);
|
||||
mdelay(2000);
|
||||
|
||||
pr_emerg("%s: unable to restart system\n", __func__);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block lpc18xx_rgu_restart_nb = {
|
||||
.notifier_call = lpc18xx_rgu_restart,
|
||||
.priority = 192,
|
||||
};
|
||||
|
||||
/*
|
||||
* The LPC18xx RGU has mostly self-deasserting resets except for the
|
||||
* two reset lines going to the internal Cortex-M0 cores.
|
||||
*
|
||||
* To prevent the M0 core resets from accidentally getting deasserted
|
||||
* status register must be check and bits in control register set to
|
||||
* preserve the state.
|
||||
*/
|
||||
static int lpc18xx_rgu_setclear_reset(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, bool set)
|
||||
{
|
||||
struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev);
|
||||
u32 stat_offset = LPC18XX_RGU_ACTIVE_STATUS0;
|
||||
u32 ctrl_offset = LPC18XX_RGU_CTRL0;
|
||||
unsigned long flags;
|
||||
u32 stat, rst_bit;
|
||||
|
||||
stat_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32);
|
||||
ctrl_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32);
|
||||
rst_bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG);
|
||||
|
||||
spin_lock_irqsave(&rc->lock, flags);
|
||||
stat = ~readl(rc->base + stat_offset);
|
||||
if (set)
|
||||
writel(stat | rst_bit, rc->base + ctrl_offset);
|
||||
else
|
||||
writel(stat & ~rst_bit, rc->base + ctrl_offset);
|
||||
spin_unlock_irqrestore(&rc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc18xx_rgu_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return lpc18xx_rgu_setclear_reset(rcdev, id, true);
|
||||
}
|
||||
|
||||
static int lpc18xx_rgu_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return lpc18xx_rgu_setclear_reset(rcdev, id, false);
|
||||
}
|
||||
|
||||
/* Only M0 cores require explicit reset deassert */
|
||||
static int lpc18xx_rgu_reset(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev);
|
||||
|
||||
lpc18xx_rgu_assert(rcdev, id);
|
||||
udelay(rc->delay_us);
|
||||
|
||||
switch (id) {
|
||||
case LPC43XX_RGU_M0SUB_RST:
|
||||
case LPC43XX_RGU_M0APP_RST:
|
||||
lpc18xx_rgu_setclear_reset(rcdev, id, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc18xx_rgu_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev);
|
||||
u32 bit, offset = LPC18XX_RGU_ACTIVE_STATUS0;
|
||||
|
||||
offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32);
|
||||
bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG);
|
||||
|
||||
return !(readl(rc->base + offset) & bit);
|
||||
}
|
||||
|
||||
static struct reset_control_ops lpc18xx_rgu_ops = {
|
||||
.reset = lpc18xx_rgu_reset,
|
||||
.assert = lpc18xx_rgu_assert,
|
||||
.deassert = lpc18xx_rgu_deassert,
|
||||
.status = lpc18xx_rgu_status,
|
||||
};
|
||||
|
||||
static int lpc18xx_rgu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_rgu_data *rc;
|
||||
struct resource *res;
|
||||
u32 fcclk, firc;
|
||||
int ret;
|
||||
|
||||
rc = devm_kzalloc(&pdev->dev, sizeof(*rc), GFP_KERNEL);
|
||||
if (!rc)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(rc->base))
|
||||
return PTR_ERR(rc->base);
|
||||
|
||||
rc->clk_reg = devm_clk_get(&pdev->dev, "reg");
|
||||
if (IS_ERR(rc->clk_reg)) {
|
||||
dev_err(&pdev->dev, "reg clock not found\n");
|
||||
return PTR_ERR(rc->clk_reg);
|
||||
}
|
||||
|
||||
rc->clk_delay = devm_clk_get(&pdev->dev, "delay");
|
||||
if (IS_ERR(rc->clk_delay)) {
|
||||
dev_err(&pdev->dev, "delay clock not found\n");
|
||||
return PTR_ERR(rc->clk_delay);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(rc->clk_reg);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable reg clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(rc->clk_delay);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable delay clock\n");
|
||||
goto dis_clk_reg;
|
||||
}
|
||||
|
||||
fcclk = clk_get_rate(rc->clk_reg) / USEC_PER_SEC;
|
||||
firc = clk_get_rate(rc->clk_delay) / USEC_PER_SEC;
|
||||
if (fcclk == 0 || firc == 0)
|
||||
rc->delay_us = 2;
|
||||
else
|
||||
rc->delay_us = DIV_ROUND_UP(fcclk, firc * firc);
|
||||
|
||||
spin_lock_init(&rc->lock);
|
||||
|
||||
rc->rcdev.owner = THIS_MODULE;
|
||||
rc->rcdev.nr_resets = 64;
|
||||
rc->rcdev.ops = &lpc18xx_rgu_ops;
|
||||
rc->rcdev.of_node = pdev->dev.of_node;
|
||||
|
||||
platform_set_drvdata(pdev, rc);
|
||||
|
||||
ret = reset_controller_register(&rc->rcdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to register device\n");
|
||||
goto dis_clks;
|
||||
}
|
||||
|
||||
rgu_base = rc->base;
|
||||
ret = register_restart_handler(&lpc18xx_rgu_restart_nb);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "failed to register restart handler\n");
|
||||
|
||||
return 0;
|
||||
|
||||
dis_clks:
|
||||
clk_disable_unprepare(rc->clk_delay);
|
||||
dis_clk_reg:
|
||||
clk_disable_unprepare(rc->clk_reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lpc18xx_rgu_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_rgu_data *rc = platform_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = unregister_restart_handler(&lpc18xx_rgu_restart_nb);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "failed to unregister restart handler\n");
|
||||
|
||||
reset_controller_unregister(&rc->rcdev);
|
||||
|
||||
clk_disable_unprepare(rc->clk_delay);
|
||||
clk_disable_unprepare(rc->clk_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id lpc18xx_rgu_match[] = {
|
||||
{ .compatible = "nxp,lpc1850-rgu" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpc18xx_rgu_match);
|
||||
|
||||
static struct platform_driver lpc18xx_rgu_driver = {
|
||||
.probe = lpc18xx_rgu_probe,
|
||||
.remove = lpc18xx_rgu_remove,
|
||||
.driver = {
|
||||
.name = "lpc18xx-reset",
|
||||
.of_match_table = lpc18xx_rgu_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lpc18xx_rgu_driver);
|
||||
|
||||
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
|
||||
MODULE_DESCRIPTION("Reset driver for LPC18xx/43xx RGU");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -24,11 +24,11 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#define NR_BANKS 4
|
||||
#define OFFSET_MODRST 0x10
|
||||
|
||||
struct socfpga_reset_data {
|
||||
spinlock_t lock;
|
||||
void __iomem *membase;
|
||||
u32 modrst_offset;
|
||||
struct reset_controller_dev rcdev;
|
||||
};
|
||||
|
||||
|
@ -45,8 +45,8 @@ static int socfpga_reset_assert(struct reset_controller_dev *rcdev,
|
|||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS));
|
||||
writel(reg | BIT(offset), data->membase + OFFSET_MODRST +
|
||||
reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
|
||||
writel(reg | BIT(offset), data->membase + data->modrst_offset +
|
||||
(bank * NR_BANKS));
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
||||
|
@ -67,8 +67,8 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev,
|
|||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
|
||||
reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS));
|
||||
writel(reg & ~BIT(offset), data->membase + OFFSET_MODRST +
|
||||
reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
|
||||
writel(reg & ~BIT(offset), data->membase + data->modrst_offset +
|
||||
(bank * NR_BANKS));
|
||||
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
|
@ -85,7 +85,7 @@ static int socfpga_reset_status(struct reset_controller_dev *rcdev,
|
|||
int offset = id % BITS_PER_LONG;
|
||||
u32 reg;
|
||||
|
||||
reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS));
|
||||
reg = readl(data->membase + data->modrst_offset + (bank * NR_BANKS));
|
||||
|
||||
return !(reg & BIT(offset));
|
||||
}
|
||||
|
@ -100,6 +100,8 @@ static int socfpga_reset_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct socfpga_reset_data *data;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
/*
|
||||
* The binding was mainlined without the required property.
|
||||
|
@ -120,6 +122,11 @@ static int socfpga_reset_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(data->membase))
|
||||
return PTR_ERR(data->membase);
|
||||
|
||||
if (of_property_read_u32(np, "altr,modrst-offset", &data->modrst_offset)) {
|
||||
dev_warn(dev, "missing altr,modrst-offset property, assuming 0x10!\n");
|
||||
data->modrst_offset = 0x10;
|
||||
}
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
data->rcdev.owner = THIS_MODULE;
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright (c) 2015, National Instruments Corp.
|
||||
*
|
||||
* Xilinx Zynq Reset controller driver
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct zynq_reset_data {
|
||||
struct regmap *slcr;
|
||||
struct reset_controller_dev rcdev;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
#define to_zynq_reset_data(p) \
|
||||
container_of((p), struct zynq_reset_data, rcdev)
|
||||
|
||||
static int zynq_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct zynq_reset_data *priv = to_zynq_reset_data(rcdev);
|
||||
|
||||
int bank = id / BITS_PER_LONG;
|
||||
int offset = id % BITS_PER_LONG;
|
||||
|
||||
pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__,
|
||||
bank, offset);
|
||||
|
||||
return regmap_update_bits(priv->slcr,
|
||||
priv->offset + (bank * 4),
|
||||
BIT(offset),
|
||||
BIT(offset));
|
||||
}
|
||||
|
||||
static int zynq_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct zynq_reset_data *priv = to_zynq_reset_data(rcdev);
|
||||
|
||||
int bank = id / BITS_PER_LONG;
|
||||
int offset = id % BITS_PER_LONG;
|
||||
|
||||
pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__,
|
||||
bank, offset);
|
||||
|
||||
return regmap_update_bits(priv->slcr,
|
||||
priv->offset + (bank * 4),
|
||||
BIT(offset),
|
||||
~BIT(offset));
|
||||
}
|
||||
|
||||
static int zynq_reset_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct zynq_reset_data *priv = to_zynq_reset_data(rcdev);
|
||||
|
||||
int bank = id / BITS_PER_LONG;
|
||||
int offset = id % BITS_PER_LONG;
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
pr_debug("%s: %s reset bank %u offset %u\n", KBUILD_MODNAME, __func__,
|
||||
bank, offset);
|
||||
|
||||
ret = regmap_read(priv->slcr, priv->offset + (bank * 4), ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return !!(reg & BIT(offset));
|
||||
}
|
||||
|
||||
static struct reset_control_ops zynq_reset_ops = {
|
||||
.assert = zynq_reset_assert,
|
||||
.deassert = zynq_reset_deassert,
|
||||
.status = zynq_reset_status,
|
||||
};
|
||||
|
||||
static int zynq_reset_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct zynq_reset_data *priv;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->slcr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
"syscon");
|
||||
if (IS_ERR(priv->slcr)) {
|
||||
dev_err(&pdev->dev, "unable to get zynq-slcr regmap");
|
||||
return PTR_ERR(priv->slcr);
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "missing IO resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->offset = res->start;
|
||||
|
||||
priv->rcdev.owner = THIS_MODULE;
|
||||
priv->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_LONG;
|
||||
priv->rcdev.ops = &zynq_reset_ops;
|
||||
priv->rcdev.of_node = pdev->dev.of_node;
|
||||
reset_controller_register(&priv->rcdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynq_reset_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct zynq_reset_data *priv = platform_get_drvdata(pdev);
|
||||
|
||||
reset_controller_unregister(&priv->rcdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id zynq_reset_dt_ids[] = {
|
||||
{ .compatible = "xlnx,zynq-reset", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver zynq_reset_driver = {
|
||||
.probe = zynq_reset_probe,
|
||||
.remove = zynq_reset_remove,
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.of_match_table = zynq_reset_dt_ids,
|
||||
},
|
||||
};
|
||||
module_platform_driver(zynq_reset_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Moritz Fischer <moritz.fischer@ettus.com>");
|
||||
MODULE_DESCRIPTION("Zynq Reset Controller Driver");
|
|
@ -11,7 +11,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <dt-bindings/reset-controller/stih407-resets.h>
|
||||
#include <dt-bindings/reset/stih407-resets.h>
|
||||
#include "reset-syscfg.h"
|
||||
|
||||
/* STiH407 Peripheral powerdown definitions. */
|
||||
|
@ -126,7 +126,7 @@ static const struct syscfg_reset_controller_data stih407_picophyreset_controller
|
|||
.channels = stih407_picophyresets,
|
||||
};
|
||||
|
||||
static struct of_device_id stih407_reset_match[] = {
|
||||
static const struct of_device_id stih407_reset_match[] = {
|
||||
{
|
||||
.compatible = "st,stih407-powerdown",
|
||||
.data = &stih407_powerdown_controller,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <dt-bindings/reset-controller/stih415-resets.h>
|
||||
#include <dt-bindings/reset/stih415-resets.h>
|
||||
|
||||
#include "reset-syscfg.h"
|
||||
|
||||
|
@ -89,7 +89,7 @@ static struct syscfg_reset_controller_data stih415_softreset_controller = {
|
|||
.channels = stih415_softresets,
|
||||
};
|
||||
|
||||
static struct of_device_id stih415_reset_match[] = {
|
||||
static const struct of_device_id stih415_reset_match[] = {
|
||||
{ .compatible = "st,stih415-powerdown",
|
||||
.data = &stih415_powerdown_controller, },
|
||||
{ .compatible = "st,stih415-softreset",
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <dt-bindings/reset-controller/stih416-resets.h>
|
||||
#include <dt-bindings/reset/stih416-resets.h>
|
||||
|
||||
#include "reset-syscfg.h"
|
||||
|
||||
|
@ -120,7 +120,7 @@ static struct syscfg_reset_controller_data stih416_softreset_controller = {
|
|||
.channels = stih416_softresets,
|
||||
};
|
||||
|
||||
static struct of_device_id stih416_reset_match[] = {
|
||||
static const struct of_device_id stih416_reset_match[] = {
|
||||
{ .compatible = "st,stih416-powerdown",
|
||||
.data = &stih416_powerdown_controller, },
|
||||
{ .compatible = "st,stih416-softreset",
|
||||
|
|
|
@ -74,6 +74,20 @@ static inline int device_reset_optional(struct device *dev)
|
|||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline struct reset_control *__must_check reset_control_get(
|
||||
struct device *dev, const char *id)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static inline struct reset_control *__must_check devm_reset_control_get(
|
||||
struct device *dev, const char *id)
|
||||
{
|
||||
WARN_ON(1);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static inline struct reset_control *reset_control_get_optional(
|
||||
struct device *dev, const char *id)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue