0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/regmap.h>
0015 #include <linux/reset-controller.h>
0016
0017 #include <dt-bindings/reset/ti-syscon.h>
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 struct ti_syscon_reset_control {
0030 unsigned int assert_offset;
0031 unsigned int assert_bit;
0032 unsigned int deassert_offset;
0033 unsigned int deassert_bit;
0034 unsigned int status_offset;
0035 unsigned int status_bit;
0036 u32 flags;
0037 };
0038
0039
0040
0041
0042
0043
0044
0045
0046 struct ti_syscon_reset_data {
0047 struct reset_controller_dev rcdev;
0048 struct regmap *regmap;
0049 struct ti_syscon_reset_control *controls;
0050 unsigned int nr_controls;
0051 };
0052
0053 #define to_ti_syscon_reset_data(_rcdev) \
0054 container_of(_rcdev, struct ti_syscon_reset_data, rcdev)
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 static int ti_syscon_reset_assert(struct reset_controller_dev *rcdev,
0067 unsigned long id)
0068 {
0069 struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
0070 struct ti_syscon_reset_control *control;
0071 unsigned int mask, value;
0072
0073 if (id >= data->nr_controls)
0074 return -EINVAL;
0075
0076 control = &data->controls[id];
0077
0078 if (control->flags & ASSERT_NONE)
0079 return -ENOTSUPP;
0080
0081 mask = BIT(control->assert_bit);
0082 value = (control->flags & ASSERT_SET) ? mask : 0x0;
0083
0084 return regmap_write_bits(data->regmap, control->assert_offset, mask, value);
0085 }
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 static int ti_syscon_reset_deassert(struct reset_controller_dev *rcdev,
0098 unsigned long id)
0099 {
0100 struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
0101 struct ti_syscon_reset_control *control;
0102 unsigned int mask, value;
0103
0104 if (id >= data->nr_controls)
0105 return -EINVAL;
0106
0107 control = &data->controls[id];
0108
0109 if (control->flags & DEASSERT_NONE)
0110 return -ENOTSUPP;
0111
0112 mask = BIT(control->deassert_bit);
0113 value = (control->flags & DEASSERT_SET) ? mask : 0x0;
0114
0115 return regmap_write_bits(data->regmap, control->deassert_offset, mask, value);
0116 }
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129 static int ti_syscon_reset_status(struct reset_controller_dev *rcdev,
0130 unsigned long id)
0131 {
0132 struct ti_syscon_reset_data *data = to_ti_syscon_reset_data(rcdev);
0133 struct ti_syscon_reset_control *control;
0134 unsigned int reset_state;
0135 int ret;
0136
0137 if (id >= data->nr_controls)
0138 return -EINVAL;
0139
0140 control = &data->controls[id];
0141
0142 if (control->flags & STATUS_NONE)
0143 return -ENOTSUPP;
0144
0145 ret = regmap_read(data->regmap, control->status_offset, &reset_state);
0146 if (ret)
0147 return ret;
0148
0149 return !(reset_state & BIT(control->status_bit)) ==
0150 !(control->flags & STATUS_SET);
0151 }
0152
0153 static const struct reset_control_ops ti_syscon_reset_ops = {
0154 .assert = ti_syscon_reset_assert,
0155 .deassert = ti_syscon_reset_deassert,
0156 .status = ti_syscon_reset_status,
0157 };
0158
0159 static int ti_syscon_reset_probe(struct platform_device *pdev)
0160 {
0161 struct device *dev = &pdev->dev;
0162 struct device_node *np = dev->of_node;
0163 struct ti_syscon_reset_data *data;
0164 struct regmap *regmap;
0165 const __be32 *list;
0166 struct ti_syscon_reset_control *controls;
0167 int size, nr_controls, i;
0168
0169 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0170 if (!data)
0171 return -ENOMEM;
0172
0173 regmap = syscon_node_to_regmap(np->parent);
0174 if (IS_ERR(regmap))
0175 return PTR_ERR(regmap);
0176
0177 list = of_get_property(np, "ti,reset-bits", &size);
0178 if (!list || (size / sizeof(*list)) % 7 != 0) {
0179 dev_err(dev, "invalid DT reset description\n");
0180 return -EINVAL;
0181 }
0182
0183 nr_controls = (size / sizeof(*list)) / 7;
0184 controls = devm_kcalloc(dev, nr_controls, sizeof(*controls),
0185 GFP_KERNEL);
0186 if (!controls)
0187 return -ENOMEM;
0188
0189 for (i = 0; i < nr_controls; i++) {
0190 controls[i].assert_offset = be32_to_cpup(list++);
0191 controls[i].assert_bit = be32_to_cpup(list++);
0192 controls[i].deassert_offset = be32_to_cpup(list++);
0193 controls[i].deassert_bit = be32_to_cpup(list++);
0194 controls[i].status_offset = be32_to_cpup(list++);
0195 controls[i].status_bit = be32_to_cpup(list++);
0196 controls[i].flags = be32_to_cpup(list++);
0197 }
0198
0199 data->rcdev.ops = &ti_syscon_reset_ops;
0200 data->rcdev.owner = THIS_MODULE;
0201 data->rcdev.of_node = np;
0202 data->rcdev.nr_resets = nr_controls;
0203 data->regmap = regmap;
0204 data->controls = controls;
0205 data->nr_controls = nr_controls;
0206
0207 platform_set_drvdata(pdev, data);
0208
0209 return devm_reset_controller_register(dev, &data->rcdev);
0210 }
0211
0212 static const struct of_device_id ti_syscon_reset_of_match[] = {
0213 { .compatible = "ti,syscon-reset", },
0214 { },
0215 };
0216 MODULE_DEVICE_TABLE(of, ti_syscon_reset_of_match);
0217
0218 static struct platform_driver ti_syscon_reset_driver = {
0219 .probe = ti_syscon_reset_probe,
0220 .driver = {
0221 .name = "ti-syscon-reset",
0222 .of_match_table = ti_syscon_reset_of_match,
0223 },
0224 };
0225 module_platform_driver(ti_syscon_reset_driver);
0226
0227 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
0228 MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
0229 MODULE_DESCRIPTION("TI SYSCON Regmap Reset Driver");
0230 MODULE_LICENSE("GPL v2");