Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * BCM6345 Reset Controller Driver
0004  *
0005  * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com>
0006  */
0007 
0008 #include <linux/delay.h>
0009 #include <linux/init.h>
0010 #include <linux/io.h>
0011 #include <linux/mod_devicetable.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/reset-controller.h>
0014 
0015 #define BCM6345_RESET_NUM       32
0016 #define BCM6345_RESET_SLEEP_MIN_US  10000
0017 #define BCM6345_RESET_SLEEP_MAX_US  20000
0018 
0019 struct bcm6345_reset {
0020     struct reset_controller_dev rcdev;
0021     void __iomem *base;
0022     spinlock_t lock;
0023 };
0024 
0025 static inline struct bcm6345_reset *
0026 to_bcm6345_reset(struct reset_controller_dev *rcdev)
0027 {
0028     return container_of(rcdev, struct bcm6345_reset, rcdev);
0029 }
0030 
0031 static int bcm6345_reset_update(struct reset_controller_dev *rcdev,
0032                 unsigned long id, bool assert)
0033 {
0034     struct bcm6345_reset *bcm6345_reset = to_bcm6345_reset(rcdev);
0035     unsigned long flags;
0036     uint32_t val;
0037 
0038     spin_lock_irqsave(&bcm6345_reset->lock, flags);
0039     val = __raw_readl(bcm6345_reset->base);
0040     if (assert)
0041         val &= ~BIT(id);
0042     else
0043         val |= BIT(id);
0044     __raw_writel(val, bcm6345_reset->base);
0045     spin_unlock_irqrestore(&bcm6345_reset->lock, flags);
0046 
0047     return 0;
0048 }
0049 
0050 static int bcm6345_reset_assert(struct reset_controller_dev *rcdev,
0051                 unsigned long id)
0052 {
0053     return bcm6345_reset_update(rcdev, id, true);
0054 }
0055 
0056 static int bcm6345_reset_deassert(struct reset_controller_dev *rcdev,
0057                   unsigned long id)
0058 {
0059     return bcm6345_reset_update(rcdev, id, false);
0060 }
0061 
0062 static int bcm6345_reset_reset(struct reset_controller_dev *rcdev,
0063                    unsigned long id)
0064 {
0065     bcm6345_reset_update(rcdev, id, true);
0066     usleep_range(BCM6345_RESET_SLEEP_MIN_US,
0067              BCM6345_RESET_SLEEP_MAX_US);
0068 
0069     bcm6345_reset_update(rcdev, id, false);
0070     /*
0071      * Ensure component is taken out reset state by sleeping also after
0072      * deasserting the reset. Otherwise, the component may not be ready
0073      * for operation.
0074      */
0075     usleep_range(BCM6345_RESET_SLEEP_MIN_US,
0076              BCM6345_RESET_SLEEP_MAX_US);
0077 
0078     return 0;
0079 }
0080 
0081 static int bcm6345_reset_status(struct reset_controller_dev *rcdev,
0082                 unsigned long id)
0083 {
0084     struct bcm6345_reset *bcm6345_reset = to_bcm6345_reset(rcdev);
0085 
0086     return !(__raw_readl(bcm6345_reset->base) & BIT(id));
0087 }
0088 
0089 static const struct reset_control_ops bcm6345_reset_ops = {
0090     .assert = bcm6345_reset_assert,
0091     .deassert = bcm6345_reset_deassert,
0092     .reset = bcm6345_reset_reset,
0093     .status = bcm6345_reset_status,
0094 };
0095 
0096 static int bcm6345_reset_probe(struct platform_device *pdev)
0097 {
0098     struct bcm6345_reset *bcm6345_reset;
0099 
0100     bcm6345_reset = devm_kzalloc(&pdev->dev,
0101                      sizeof(*bcm6345_reset), GFP_KERNEL);
0102     if (!bcm6345_reset)
0103         return -ENOMEM;
0104 
0105     platform_set_drvdata(pdev, bcm6345_reset);
0106 
0107     bcm6345_reset->base = devm_platform_ioremap_resource(pdev, 0);
0108     if (IS_ERR(bcm6345_reset->base))
0109         return PTR_ERR(bcm6345_reset->base);
0110 
0111     spin_lock_init(&bcm6345_reset->lock);
0112     bcm6345_reset->rcdev.ops = &bcm6345_reset_ops;
0113     bcm6345_reset->rcdev.owner = THIS_MODULE;
0114     bcm6345_reset->rcdev.of_node = pdev->dev.of_node;
0115     bcm6345_reset->rcdev.of_reset_n_cells = 1;
0116     bcm6345_reset->rcdev.nr_resets = BCM6345_RESET_NUM;
0117 
0118     return devm_reset_controller_register(&pdev->dev,
0119                           &bcm6345_reset->rcdev);
0120 }
0121 
0122 static const struct of_device_id bcm6345_reset_of_match[] = {
0123     { .compatible = "brcm,bcm6345-reset" },
0124     { /* sentinel */ },
0125 };
0126 
0127 static struct platform_driver bcm6345_reset_driver = {
0128     .probe = bcm6345_reset_probe,
0129     .driver = {
0130         .name = "bcm6345-reset",
0131         .of_match_table = bcm6345_reset_of_match,
0132         .suppress_bind_attrs = true,
0133     },
0134 };
0135 builtin_platform_driver(bcm6345_reset_driver);