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