brintos

brintos / linux-shallow public Read only

0
0
Text · 4.6 KiB · 2324060 Raw
198 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2013 STMicroelectronics Limited4 * Author: Stephen Gallimore <stephen.gallimore@st.com>5 *6 * Inspired by mach-imx/src.c7 */8#include <linux/kernel.h>9#include <linux/platform_device.h>10#include <linux/property.h>11#include <linux/module.h>12#include <linux/err.h>13#include <linux/types.h>14#include <linux/of.h>15#include <linux/regmap.h>16#include <linux/mfd/syscon.h>17 18#include "reset-syscfg.h"19 20/**21 * struct syscfg_reset_channel - Reset channel regmap configuration22 *23 * @reset: regmap field for the channel's reset bit.24 * @ack: regmap field for the channel's ack bit (optional).25 */26struct syscfg_reset_channel {27	struct regmap_field *reset;28	struct regmap_field *ack;29};30 31/**32 * struct syscfg_reset_controller - A reset controller which groups together33 * a set of related reset bits, which may be located in different system34 * configuration registers.35 *36 * @rst: base reset controller structure.37 * @active_low: are the resets in this controller active low, i.e. clearing38 *              the reset bit puts the hardware into reset.39 * @channels: An array of reset channels for this controller.40 */41struct syscfg_reset_controller {42	struct reset_controller_dev rst;43	bool active_low;44	struct syscfg_reset_channel *channels;45};46 47#define to_syscfg_reset_controller(_rst) \48	container_of(_rst, struct syscfg_reset_controller, rst)49 50static int syscfg_reset_program_hw(struct reset_controller_dev *rcdev,51				   unsigned long idx, int assert)52{53	struct syscfg_reset_controller *rst = to_syscfg_reset_controller(rcdev);54	const struct syscfg_reset_channel *ch;55	u32 ctrl_val = rst->active_low ? !assert : !!assert;56	int err;57 58	if (idx >= rcdev->nr_resets)59		return -EINVAL;60 61	ch = &rst->channels[idx];62 63	err = regmap_field_write(ch->reset, ctrl_val);64	if (err)65		return err;66 67	if (ch->ack) {68		u32 ack_val;69 70		err = regmap_field_read_poll_timeout(ch->ack, ack_val, (ack_val == ctrl_val),71						     100, USEC_PER_SEC);72		if (err)73			return err;74	}75 76	return 0;77}78 79static int syscfg_reset_assert(struct reset_controller_dev *rcdev,80			       unsigned long idx)81{82	return syscfg_reset_program_hw(rcdev, idx, true);83}84 85static int syscfg_reset_deassert(struct reset_controller_dev *rcdev,86				 unsigned long idx)87{88	return syscfg_reset_program_hw(rcdev, idx, false);89}90 91static int syscfg_reset_dev(struct reset_controller_dev *rcdev,92			    unsigned long idx)93{94	int err;95 96	err = syscfg_reset_assert(rcdev, idx);97	if (err)98		return err;99 100	return syscfg_reset_deassert(rcdev, idx);101}102 103static int syscfg_reset_status(struct reset_controller_dev *rcdev,104			       unsigned long idx)105{106	struct syscfg_reset_controller *rst = to_syscfg_reset_controller(rcdev);107	const struct syscfg_reset_channel *ch;108	u32 ret_val = 0;109	int err;110 111	if (idx >= rcdev->nr_resets)112		return -EINVAL;113 114	ch = &rst->channels[idx];115	if (ch->ack)116		err = regmap_field_read(ch->ack, &ret_val);117	else118		err = regmap_field_read(ch->reset, &ret_val);119	if (err)120		return err;121 122	return rst->active_low ? !ret_val : !!ret_val;123}124 125static const struct reset_control_ops syscfg_reset_ops = {126	.reset    = syscfg_reset_dev,127	.assert   = syscfg_reset_assert,128	.deassert = syscfg_reset_deassert,129	.status   = syscfg_reset_status,130};131 132static int syscfg_reset_controller_register(struct device *dev,133				const struct syscfg_reset_controller_data *data)134{135	struct syscfg_reset_controller *rc;136	int i, err;137 138	rc = devm_kzalloc(dev, sizeof(*rc), GFP_KERNEL);139	if (!rc)140		return -ENOMEM;141 142	rc->channels = devm_kcalloc(dev, data->nr_channels,143				    sizeof(*rc->channels), GFP_KERNEL);144	if (!rc->channels)145		return -ENOMEM;146 147	rc->rst.ops = &syscfg_reset_ops;148	rc->rst.of_node = dev->of_node;149	rc->rst.nr_resets = data->nr_channels;150	rc->active_low = data->active_low;151 152	for (i = 0; i < data->nr_channels; i++) {153		struct regmap *map;154		struct regmap_field *f;155		const char *compatible = data->channels[i].compatible;156 157		map = syscon_regmap_lookup_by_compatible(compatible);158		if (IS_ERR(map))159			return PTR_ERR(map);160 161		f = devm_regmap_field_alloc(dev, map, data->channels[i].reset);162		if (IS_ERR(f))163			return PTR_ERR(f);164 165		rc->channels[i].reset = f;166 167		if (!data->wait_for_ack)168			continue;169 170		f = devm_regmap_field_alloc(dev, map, data->channels[i].ack);171		if (IS_ERR(f))172			return PTR_ERR(f);173 174		rc->channels[i].ack = f;175	}176 177	err = reset_controller_register(&rc->rst);178	if (!err)179		dev_info(dev, "registered\n");180 181	return err;182}183 184int syscfg_reset_probe(struct platform_device *pdev)185{186	struct device *dev = pdev ? &pdev->dev : NULL;187	const void *data;188 189	if (!dev || !dev->driver)190		return -ENODEV;191 192	data = device_get_match_data(&pdev->dev);193	if (!data)194		return -EINVAL;195 196	return syscfg_reset_controller_register(dev, data);197}198