Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /*
0003  * Amlogic Meson Reset Controller driver
0004  *
0005  * Copyright (c) 2016 BayLibre, SAS.
0006  * Author: Neil Armstrong <narmstrong@baylibre.com>
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      { /* sentinel */ },
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");