Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /*
0003  * SP7021 reset driver
0004  *
0005  * Copyright (C) Sunplus Technology Co., Ltd.
0006  *       All rights reserved.
0007  */
0008 
0009 #include <linux/io.h>
0010 #include <linux/init.h>
0011 #include <linux/mod_devicetable.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/reset-controller.h>
0014 #include <linux/reboot.h>
0015 
0016 /* HIWORD_MASK_REG BITS */
0017 #define BITS_PER_HWM_REG    16
0018 
0019 /* resets HW info: reg_index_shift */
0020 static const u32 sp_resets[] = {
0021 /* SP7021: mo_reset0 ~ mo_reset9 */
0022     0x00,
0023     0x02,
0024     0x03,
0025     0x04,
0026     0x05,
0027     0x06,
0028     0x07,
0029     0x08,
0030     0x09,
0031     0x0a,
0032     0x0b,
0033     0x0d,
0034     0x0e,
0035     0x0f,
0036     0x10,
0037     0x12,
0038     0x14,
0039     0x15,
0040     0x16,
0041     0x17,
0042     0x18,
0043     0x19,
0044     0x1a,
0045     0x1b,
0046     0x1c,
0047     0x1d,
0048     0x1e,
0049     0x1f,
0050     0x20,
0051     0x21,
0052     0x22,
0053     0x23,
0054     0x24,
0055     0x25,
0056     0x26,
0057     0x2a,
0058     0x2b,
0059     0x2d,
0060     0x2e,
0061     0x30,
0062     0x31,
0063     0x32,
0064     0x33,
0065     0x3d,
0066     0x3e,
0067     0x3f,
0068     0x42,
0069     0x44,
0070     0x4b,
0071     0x4c,
0072     0x4d,
0073     0x4e,
0074     0x4f,
0075     0x50,
0076     0x55,
0077     0x60,
0078     0x61,
0079     0x6a,
0080     0x6f,
0081     0x70,
0082     0x73,
0083     0x74,
0084     0x86,
0085     0x8a,
0086     0x8b,
0087     0x8d,
0088     0x8e,
0089     0x8f,
0090     0x90,
0091     0x92,
0092     0x93,
0093     0x94,
0094     0x95,
0095     0x96,
0096     0x97,
0097     0x98,
0098     0x99,
0099 };
0100 
0101 struct sp_reset {
0102     struct reset_controller_dev rcdev;
0103     struct notifier_block notifier;
0104     void __iomem *base;
0105 };
0106 
0107 static inline struct sp_reset *to_sp_reset(struct reset_controller_dev *rcdev)
0108 {
0109     return container_of(rcdev, struct sp_reset, rcdev);
0110 }
0111 
0112 static int sp_reset_update(struct reset_controller_dev *rcdev,
0113                unsigned long id, bool assert)
0114 {
0115     struct sp_reset *reset = to_sp_reset(rcdev);
0116     int index = sp_resets[id] / BITS_PER_HWM_REG;
0117     int shift = sp_resets[id] % BITS_PER_HWM_REG;
0118     u32 val;
0119 
0120     val = (1 << (16 + shift)) | (assert << shift);
0121     writel(val, reset->base + (index * 4));
0122 
0123     return 0;
0124 }
0125 
0126 static int sp_reset_assert(struct reset_controller_dev *rcdev,
0127                unsigned long id)
0128 {
0129     return sp_reset_update(rcdev, id, true);
0130 }
0131 
0132 static int sp_reset_deassert(struct reset_controller_dev *rcdev,
0133                  unsigned long id)
0134 {
0135     return sp_reset_update(rcdev, id, false);
0136 }
0137 
0138 static int sp_reset_status(struct reset_controller_dev *rcdev,
0139                unsigned long id)
0140 {
0141     struct sp_reset *reset = to_sp_reset(rcdev);
0142     int index = sp_resets[id] / BITS_PER_HWM_REG;
0143     int shift = sp_resets[id] % BITS_PER_HWM_REG;
0144     u32 reg;
0145 
0146     reg = readl(reset->base + (index * 4));
0147 
0148     return !!(reg & BIT(shift));
0149 }
0150 
0151 static const struct reset_control_ops sp_reset_ops = {
0152     .assert   = sp_reset_assert,
0153     .deassert = sp_reset_deassert,
0154     .status   = sp_reset_status,
0155 };
0156 
0157 static int sp_restart(struct notifier_block *nb, unsigned long mode,
0158               void *cmd)
0159 {
0160     struct sp_reset *reset = container_of(nb, struct sp_reset, notifier);
0161 
0162     sp_reset_assert(&reset->rcdev, 0);
0163     sp_reset_deassert(&reset->rcdev, 0);
0164 
0165     return NOTIFY_DONE;
0166 }
0167 
0168 static int sp_reset_probe(struct platform_device *pdev)
0169 {
0170     struct device *dev = &pdev->dev;
0171     struct sp_reset *reset;
0172     struct resource *res;
0173     int ret;
0174 
0175     reset = devm_kzalloc(dev, sizeof(*reset), GFP_KERNEL);
0176     if (!reset)
0177         return -ENOMEM;
0178 
0179     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0180     reset->base = devm_ioremap_resource(dev, res);
0181     if (IS_ERR(reset->base))
0182         return PTR_ERR(reset->base);
0183 
0184     reset->rcdev.ops = &sp_reset_ops;
0185     reset->rcdev.owner = THIS_MODULE;
0186     reset->rcdev.of_node = dev->of_node;
0187     reset->rcdev.nr_resets = resource_size(res) / 4 * BITS_PER_HWM_REG;
0188 
0189     ret = devm_reset_controller_register(dev, &reset->rcdev);
0190     if (ret)
0191         return ret;
0192 
0193     reset->notifier.notifier_call = sp_restart;
0194     reset->notifier.priority = 192;
0195 
0196     return register_restart_handler(&reset->notifier);
0197 }
0198 
0199 static const struct of_device_id sp_reset_dt_ids[] = {
0200     {.compatible = "sunplus,sp7021-reset",},
0201     { /* sentinel */ },
0202 };
0203 
0204 static struct platform_driver sp_reset_driver = {
0205     .probe = sp_reset_probe,
0206     .driver = {
0207         .name           = "sunplus-reset",
0208         .of_match_table     = sp_reset_dt_ids,
0209         .suppress_bind_attrs    = true,
0210     },
0211 };
0212 builtin_platform_driver(sp_reset_driver);