brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · 65aa5ff Raw
224 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Hisilicon Hi6220 reset controller driver4 *5 * Copyright (c) 2016 Linaro Limited.6 * Copyright (c) 2015-2016 HiSilicon Limited.7 *8 * Author: Feng Chen <puck.chen@hisilicon.com>9 */10 11#include <linux/io.h>12#include <linux/init.h>13#include <linux/module.h>14#include <linux/bitops.h>15#include <linux/of.h>16#include <linux/regmap.h>17#include <linux/mfd/syscon.h>18#include <linux/reset-controller.h>19#include <linux/reset.h>20#include <linux/platform_device.h>21 22#define PERIPH_ASSERT_OFFSET      0x30023#define PERIPH_DEASSERT_OFFSET    0x30424#define PERIPH_MAX_INDEX          0x50925 26#define SC_MEDIA_RSTEN            0x052C27#define SC_MEDIA_RSTDIS           0x053028#define MEDIA_MAX_INDEX           829 30#define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev)31 32enum hi6220_reset_ctrl_type {33	PERIPHERAL,34	MEDIA,35	AO,36};37 38struct hi6220_reset_data {39	struct reset_controller_dev rc_dev;40	struct regmap *regmap;41};42 43static int hi6220_peripheral_assert(struct reset_controller_dev *rc_dev,44				    unsigned long idx)45{46	struct hi6220_reset_data *data = to_reset_data(rc_dev);47	struct regmap *regmap = data->regmap;48	u32 bank = idx >> 8;49	u32 offset = idx & 0xff;50	u32 reg = PERIPH_ASSERT_OFFSET + bank * 0x10;51 52	return regmap_write(regmap, reg, BIT(offset));53}54 55static int hi6220_peripheral_deassert(struct reset_controller_dev *rc_dev,56				      unsigned long idx)57{58	struct hi6220_reset_data *data = to_reset_data(rc_dev);59	struct regmap *regmap = data->regmap;60	u32 bank = idx >> 8;61	u32 offset = idx & 0xff;62	u32 reg = PERIPH_DEASSERT_OFFSET + bank * 0x10;63 64	return regmap_write(regmap, reg, BIT(offset));65}66 67static const struct reset_control_ops hi6220_peripheral_reset_ops = {68	.assert = hi6220_peripheral_assert,69	.deassert = hi6220_peripheral_deassert,70};71 72static int hi6220_media_assert(struct reset_controller_dev *rc_dev,73			       unsigned long idx)74{75	struct hi6220_reset_data *data = to_reset_data(rc_dev);76	struct regmap *regmap = data->regmap;77 78	return regmap_write(regmap, SC_MEDIA_RSTEN, BIT(idx));79}80 81static int hi6220_media_deassert(struct reset_controller_dev *rc_dev,82				 unsigned long idx)83{84	struct hi6220_reset_data *data = to_reset_data(rc_dev);85	struct regmap *regmap = data->regmap;86 87	return regmap_write(regmap, SC_MEDIA_RSTDIS, BIT(idx));88}89 90static const struct reset_control_ops hi6220_media_reset_ops = {91	.assert = hi6220_media_assert,92	.deassert = hi6220_media_deassert,93};94 95#define AO_SCTRL_SC_PW_CLKEN0     0x80096#define AO_SCTRL_SC_PW_CLKDIS0    0x80497 98#define AO_SCTRL_SC_PW_RSTEN0     0x81099#define AO_SCTRL_SC_PW_RSTDIS0    0x814100 101#define AO_SCTRL_SC_PW_ISOEN0     0x820102#define AO_SCTRL_SC_PW_ISODIS0    0x824103#define AO_MAX_INDEX              12104 105static int hi6220_ao_assert(struct reset_controller_dev *rc_dev,106			       unsigned long idx)107{108	struct hi6220_reset_data *data = to_reset_data(rc_dev);109	struct regmap *regmap = data->regmap;110	int ret;111 112	ret = regmap_write(regmap, AO_SCTRL_SC_PW_RSTEN0, BIT(idx));113	if (ret)114		return ret;115 116	ret = regmap_write(regmap, AO_SCTRL_SC_PW_ISOEN0, BIT(idx));117	if (ret)118		return ret;119 120	ret = regmap_write(regmap, AO_SCTRL_SC_PW_CLKDIS0, BIT(idx));121	return ret;122}123 124static int hi6220_ao_deassert(struct reset_controller_dev *rc_dev,125				 unsigned long idx)126{127	struct hi6220_reset_data *data = to_reset_data(rc_dev);128	struct regmap *regmap = data->regmap;129	int ret;130 131	/*132	 * It was suggested to disable isolation before enabling133	 * the clocks and deasserting reset, to avoid glitches.134	 * But this order is preserved to keep it matching the135	 * vendor code.136	 */137	ret = regmap_write(regmap, AO_SCTRL_SC_PW_RSTDIS0, BIT(idx));138	if (ret)139		return ret;140 141	ret = regmap_write(regmap, AO_SCTRL_SC_PW_ISODIS0, BIT(idx));142	if (ret)143		return ret;144 145	ret = regmap_write(regmap, AO_SCTRL_SC_PW_CLKEN0, BIT(idx));146	return ret;147}148 149static const struct reset_control_ops hi6220_ao_reset_ops = {150	.assert = hi6220_ao_assert,151	.deassert = hi6220_ao_deassert,152};153 154static int hi6220_reset_probe(struct platform_device *pdev)155{156	struct device_node *np = pdev->dev.of_node;157	struct device *dev = &pdev->dev;158	enum hi6220_reset_ctrl_type type;159	struct hi6220_reset_data *data;160	struct regmap *regmap;161 162	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);163	if (!data)164		return -ENOMEM;165 166	type = (uintptr_t)of_device_get_match_data(dev);167 168	regmap = syscon_node_to_regmap(np);169	if (IS_ERR(regmap)) {170		dev_err(dev, "failed to get reset controller regmap\n");171		return PTR_ERR(regmap);172	}173 174	data->regmap = regmap;175	data->rc_dev.of_node = np;176	if (type == MEDIA) {177		data->rc_dev.ops = &hi6220_media_reset_ops;178		data->rc_dev.nr_resets = MEDIA_MAX_INDEX;179	} else if (type == PERIPHERAL) {180		data->rc_dev.ops = &hi6220_peripheral_reset_ops;181		data->rc_dev.nr_resets = PERIPH_MAX_INDEX;182	} else {183		data->rc_dev.ops = &hi6220_ao_reset_ops;184		data->rc_dev.nr_resets = AO_MAX_INDEX;185	}186 187	return reset_controller_register(&data->rc_dev);188}189 190static const struct of_device_id hi6220_reset_match[] = {191	{192		.compatible = "hisilicon,hi6220-sysctrl",193		.data = (void *)PERIPHERAL,194	},195	{196		.compatible = "hisilicon,hi6220-mediactrl",197		.data = (void *)MEDIA,198	},199	{200		.compatible = "hisilicon,hi6220-aoctrl",201		.data = (void *)AO,202	},203	{ /* sentinel */ },204};205MODULE_DEVICE_TABLE(of, hi6220_reset_match);206 207static struct platform_driver hi6220_reset_driver = {208	.probe = hi6220_reset_probe,209	.driver = {210		.name = "reset-hi6220",211		.of_match_table = hi6220_reset_match,212	},213};214 215static int __init hi6220_reset_init(void)216{217	return platform_driver_register(&hi6220_reset_driver);218}219 220postcore_initcall(hi6220_reset_init);221 222MODULE_DESCRIPTION("Hisilicon Hi6220 reset controller driver");223MODULE_LICENSE("GPL v2");224