Messages in this thread Patch in this message |  | | From | James Tai <> | Subject | [PATCH 4/6] clk: realtek: add reset controller support for Realtek SoCs | Date | Tue, 3 Dec 2019 15:35:38 +0800 |
| |
From: cylee12 <cylee12@realtek.com>
This patch add reset control support for Realtek SoCs.
Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com> Signed-off-by: James Tai <james.tai@realtek.com> --- drivers/clk/realtek/Kconfig | 1 + drivers/clk/realtek/Makefile | 1 + drivers/clk/realtek/reset.c | 107 +++++++++++++++++++++++++++++++++++ drivers/clk/realtek/reset.h | 37 ++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 drivers/clk/realtek/reset.c create mode 100644 drivers/clk/realtek/reset.h
diff --git a/drivers/clk/realtek/Kconfig b/drivers/clk/realtek/Kconfig index 5bca757dddfa..8e7e7edf64dd 100644 --- a/drivers/clk/realtek/Kconfig +++ b/drivers/clk/realtek/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config COMMON_CLK_REALTEK bool "Clock driver for realtek" + select RESET_CONTROLLER select MFD_SYSCON config CLK_PLL_PSAUD diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile index 050d450db067..43f8bd71c0c8 100644 --- a/drivers/clk/realtek/Makefile +++ b/drivers/clk/realtek/Makefile @@ -7,3 +7,4 @@ clk-rtk-y += clk-regmap-gate.o clk-rtk-y += clk-pll.o clk-rtk-$(CONFIG_CLK_PLL_PSAUD) += clk-pll-psaud.o clk-rtk-$(CONFIG_CLK_PLL_DIF) += clk-pll-dif.o +clk-rtk-y += reset.o diff --git a/drivers/clk/realtek/reset.c b/drivers/clk/realtek/reset.c new file mode 100644 index 000000000000..3f4d1a723b2a --- /dev/null +++ b/drivers/clk/realtek/reset.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + */ + +#include <linux/of.h> +#include <linux/device.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> +#include <linux/slab.h> +#include "reset.h" + +static int rtk_reset_assert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct rtk_reset_data *data = to_rtk_reset_controller(rcdev); + struct rtk_reset_bank *bank = &data->banks[idx >> 8]; + uint32_t id = idx & 0xff; + uint32_t mask = bank->write_en ? (0x3 << id) : BIT(id); + uint32_t val = bank->write_en ? (0x2 << id) : 0; + + return regmap_update_bits(data->regmap, bank->ofs, mask, val); +} + +static int rtk_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct rtk_reset_data *data = to_rtk_reset_controller(rcdev); + struct rtk_reset_bank *bank = &data->banks[idx >> 8]; + uint32_t id = idx & 0xff; + uint32_t mask = bank->write_en ? (0x3 << id) : BIT(id); + uint32_t val = mask; + + return regmap_update_bits(data->regmap, bank->ofs, mask, val); +} + +static int rtk_reset_reset(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + int ret; + + ret = rtk_reset_assert(rcdev, idx); + if (ret) + return ret; + + return rtk_reset_deassert(rcdev, idx); +} + +static int rtk_reset_status(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct rtk_reset_data *data = to_rtk_reset_controller(rcdev); + struct rtk_reset_bank *bank = &data->banks[idx >> 8]; + uint32_t id = idx & 0xff; + uint32_t val; + + regmap_read(data->regmap, bank->ofs, &val); + return !((val >> id) & 1); +} + +static struct reset_control_ops rtk_reset_ops = { + .assert = rtk_reset_assert, + .deassert = rtk_reset_deassert, + .reset = rtk_reset_reset, + .status = rtk_reset_status, +}; + +static int rtk_of_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + struct rtk_reset_data *data = to_rtk_reset_controller(rcdev); + int val; + + val = reset_spec->args[0]; + if (val >= rcdev->nr_resets) + return -EINVAL; + + if (data->id_xlate) + return data->id_xlate(val); + return val; +} + + +int rtk_reset_controller_add(struct device *dev, struct regmap *regmap, + struct rtk_reset_initdata *initdata) +{ + struct rtk_reset_data *data; + struct device_node *np = dev->of_node; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + data->regmap = regmap; + data->num_banks = initdata->num_banks; + data->banks = initdata->banks; + data->id_xlate = initdata->id_xlate; + + data->rcdev.owner = THIS_MODULE; + data->rcdev.ops = &rtk_reset_ops; + data->rcdev.of_node = np; + data->rcdev.nr_resets = initdata->num_banks * 0x100; + data->rcdev.of_xlate = rtk_of_reset_xlate; + data->rcdev.of_reset_n_cells = 1; + + return reset_controller_register(&data->rcdev); +} + diff --git a/drivers/clk/realtek/reset.h b/drivers/clk/realtek/reset.h new file mode 100644 index 000000000000..f0cc7b1045ee --- /dev/null +++ b/drivers/clk/realtek/reset.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2019 Realtek Semiconductor Corporation + * Author: Cheng-Yu Lee <cylee12@realtek.com> + */ + +#ifndef __CLK_REALTEK_RESET_H +#define __CLK_REALTEK_RESET_H + +#include <linux/reset-controller.h> + +struct rtk_reset_bank { + uint32_t ofs; + uint32_t write_en; +}; + +struct rtk_reset_data { + struct reset_controller_dev rcdev; + struct rtk_reset_bank *banks; + uint32_t num_banks; + struct regmap *regmap; + unsigned long (*id_xlate)(unsigned long id); +}; + +#define to_rtk_reset_controller(r) \ + container_of(r, struct rtk_reset_data, rcdev) + +struct rtk_reset_initdata { + struct rtk_reset_bank *banks; + uint32_t num_banks; + unsigned long (*id_xlate)(unsigned long id); +}; + +int rtk_reset_controller_add(struct device *dev, struct regmap *regmap, + struct rtk_reset_initdata *initdata); + +#endif /* __CLK_REALTEK_RESET_H */ -- 2.24.0
|  |