0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/err.h>
0009 #include <linux/init.h>
0010 #include <linux/io.h>
0011 #include <linux/of.h>
0012 #include <linux/module.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/reset-controller.h>
0015 #include <linux/slab.h>
0016 #include <linux/types.h>
0017 #include <linux/of_device.h>
0018
0019 #define BITS_PER_REG 32
0020
0021 struct meson_reset_param {
0022 int reg_count;
0023 int level_offset;
0024 };
0025
0026 struct meson_reset {
0027 void __iomem *reg_base;
0028 const struct meson_reset_param *param;
0029 struct reset_controller_dev rcdev;
0030 spinlock_t lock;
0031 };
0032
0033 static int meson_reset_reset(struct reset_controller_dev *rcdev,
0034 unsigned long id)
0035 {
0036 struct meson_reset *data =
0037 container_of(rcdev, struct meson_reset, rcdev);
0038 unsigned int bank = id / BITS_PER_REG;
0039 unsigned int offset = id % BITS_PER_REG;
0040 void __iomem *reg_addr = data->reg_base + (bank << 2);
0041
0042 writel(BIT(offset), reg_addr);
0043
0044 return 0;
0045 }
0046
0047 static int meson_reset_level(struct reset_controller_dev *rcdev,
0048 unsigned long id, bool assert)
0049 {
0050 struct meson_reset *data =
0051 container_of(rcdev, struct meson_reset, rcdev);
0052 unsigned int bank = id / BITS_PER_REG;
0053 unsigned int offset = id % BITS_PER_REG;
0054 void __iomem *reg_addr;
0055 unsigned long flags;
0056 u32 reg;
0057
0058 reg_addr = data->reg_base + data->param->level_offset + (bank << 2);
0059
0060 spin_lock_irqsave(&data->lock, flags);
0061
0062 reg = readl(reg_addr);
0063 if (assert)
0064 writel(reg & ~BIT(offset), reg_addr);
0065 else
0066 writel(reg | BIT(offset), reg_addr);
0067
0068 spin_unlock_irqrestore(&data->lock, flags);
0069
0070 return 0;
0071 }
0072
0073 static int meson_reset_assert(struct reset_controller_dev *rcdev,
0074 unsigned long id)
0075 {
0076 return meson_reset_level(rcdev, id, true);
0077 }
0078
0079 static int meson_reset_deassert(struct reset_controller_dev *rcdev,
0080 unsigned long id)
0081 {
0082 return meson_reset_level(rcdev, id, false);
0083 }
0084
0085 static const struct reset_control_ops meson_reset_ops = {
0086 .reset = meson_reset_reset,
0087 .assert = meson_reset_assert,
0088 .deassert = meson_reset_deassert,
0089 };
0090
0091 static const struct meson_reset_param meson8b_param = {
0092 .reg_count = 8,
0093 .level_offset = 0x7c,
0094 };
0095
0096 static const struct meson_reset_param meson_a1_param = {
0097 .reg_count = 3,
0098 .level_offset = 0x40,
0099 };
0100
0101 static const struct meson_reset_param meson_s4_param = {
0102 .reg_count = 6,
0103 .level_offset = 0x40,
0104 };
0105
0106 static const struct of_device_id meson_reset_dt_ids[] = {
0107 { .compatible = "amlogic,meson8b-reset", .data = &meson8b_param},
0108 { .compatible = "amlogic,meson-gxbb-reset", .data = &meson8b_param},
0109 { .compatible = "amlogic,meson-axg-reset", .data = &meson8b_param},
0110 { .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param},
0111 { .compatible = "amlogic,meson-s4-reset", .data = &meson_s4_param},
0112 { },
0113 };
0114 MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
0115
0116 static int meson_reset_probe(struct platform_device *pdev)
0117 {
0118 struct meson_reset *data;
0119 struct resource *res;
0120
0121 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0122 if (!data)
0123 return -ENOMEM;
0124
0125 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0126 data->reg_base = devm_ioremap_resource(&pdev->dev, res);
0127 if (IS_ERR(data->reg_base))
0128 return PTR_ERR(data->reg_base);
0129
0130 data->param = of_device_get_match_data(&pdev->dev);
0131 if (!data->param)
0132 return -ENODEV;
0133
0134 platform_set_drvdata(pdev, data);
0135
0136 spin_lock_init(&data->lock);
0137
0138 data->rcdev.owner = THIS_MODULE;
0139 data->rcdev.nr_resets = data->param->reg_count * BITS_PER_REG;
0140 data->rcdev.ops = &meson_reset_ops;
0141 data->rcdev.of_node = pdev->dev.of_node;
0142
0143 return devm_reset_controller_register(&pdev->dev, &data->rcdev);
0144 }
0145
0146 static struct platform_driver meson_reset_driver = {
0147 .probe = meson_reset_probe,
0148 .driver = {
0149 .name = "meson_reset",
0150 .of_match_table = meson_reset_dt_ids,
0151 },
0152 };
0153 module_platform_driver(meson_reset_driver);
0154
0155 MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver");
0156 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0157 MODULE_LICENSE("Dual BSD/GPL");