1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * BCM6345 Reset Controller Driver 4 * 5 * Copyright (C) 2020 Álvaro Fernández Rojas <noltari@gmail.com> 6 */ 7 8 #include <linux/delay.h> 9 #include <linux/init.h> 10 #include <linux/io.h> 11 #include <linux/platform_device.h> 12 #include <linux/reset-controller.h> 13 14 #define BCM6345_RESET_NUM 32 15 #define BCM6345_RESET_SLEEP_MIN_US 10000 16 #define BCM6345_RESET_SLEEP_MAX_US 20000 17 18 struct bcm6345_reset { 19 struct reset_controller_dev rcdev; 20 void __iomem *base; 21 spinlock_t lock; 22 }; 23 24 static inline struct bcm6345_reset * 25 to_bcm6345_reset(struct reset_controller_dev *rcdev) 26 { 27 return container_of(rcdev, struct bcm6345_reset, rcdev); 28 } 29 30 static int bcm6345_reset_update(struct reset_controller_dev *rcdev, 31 unsigned long id, bool assert) 32 { 33 struct bcm6345_reset *bcm6345_reset = to_bcm6345_reset(rcdev); 34 unsigned long flags; 35 uint32_t val; 36 37 spin_lock_irqsave(&bcm6345_reset->lock, flags); 38 val = __raw_readl(bcm6345_reset->base); 39 if (assert) 40 val &= ~BIT(id); 41 else 42 val |= BIT(id); 43 __raw_writel(val, bcm6345_reset->base); 44 spin_unlock_irqrestore(&bcm6345_reset->lock, flags); 45 46 return 0; 47 } 48 49 static int bcm6345_reset_assert(struct reset_controller_dev *rcdev, 50 unsigned long id) 51 { 52 return bcm6345_reset_update(rcdev, id, true); 53 } 54 55 static int bcm6345_reset_deassert(struct reset_controller_dev *rcdev, 56 unsigned long id) 57 { 58 return bcm6345_reset_update(rcdev, id, false); 59 } 60 61 static int bcm6345_reset_reset(struct reset_controller_dev *rcdev, 62 unsigned long id) 63 { 64 bcm6345_reset_update(rcdev, id, true); 65 usleep_range(BCM6345_RESET_SLEEP_MIN_US, 66 BCM6345_RESET_SLEEP_MAX_US); 67 68 bcm6345_reset_update(rcdev, id, false); 69 /* 70 * Ensure component is taken out reset state by sleeping also after 71 * deasserting the reset. Otherwise, the component may not be ready 72 * for operation. 73 */ 74 usleep_range(BCM6345_RESET_SLEEP_MIN_US, 75 BCM6345_RESET_SLEEP_MAX_US); 76 77 return 0; 78 } 79 80 static int bcm6345_reset_status(struct reset_controller_dev *rcdev, 81 unsigned long id) 82 { 83 struct bcm6345_reset *bcm6345_reset = to_bcm6345_reset(rcdev); 84 85 return !(__raw_readl(bcm6345_reset->base) & BIT(id)); 86 } 87 88 static const struct reset_control_ops bcm6345_reset_ops = { 89 .assert = bcm6345_reset_assert, 90 .deassert = bcm6345_reset_deassert, 91 .reset = bcm6345_reset_reset, 92 .status = bcm6345_reset_status, 93 }; 94 95 static int bcm6345_reset_probe(struct platform_device *pdev) 96 { 97 struct bcm6345_reset *bcm6345_reset; 98 99 bcm6345_reset = devm_kzalloc(&pdev->dev, 100 sizeof(*bcm6345_reset), GFP_KERNEL); 101 if (!bcm6345_reset) 102 return -ENOMEM; 103 104 bcm6345_reset->base = devm_platform_ioremap_resource(pdev, 0); 105 if (IS_ERR(bcm6345_reset->base)) 106 return PTR_ERR(bcm6345_reset->base); 107 108 spin_lock_init(&bcm6345_reset->lock); 109 bcm6345_reset->rcdev.ops = &bcm6345_reset_ops; 110 bcm6345_reset->rcdev.owner = THIS_MODULE; 111 bcm6345_reset->rcdev.of_node = pdev->dev.of_node; 112 bcm6345_reset->rcdev.of_reset_n_cells = 1; 113 bcm6345_reset->rcdev.nr_resets = BCM6345_RESET_NUM; 114 115 return devm_reset_controller_register(&pdev->dev, 116 &bcm6345_reset->rcdev); 117 } 118 119 static const struct of_device_id bcm6345_reset_of_match[] = { 120 { .compatible = "brcm,bcm6345-reset" }, 121 { .compatible = "brcm,bcm63xx-ephy-ctrl" }, 122 { /* sentinel */ }, 123 }; 124 125 static struct platform_driver bcm6345_reset_driver = { 126 .probe = bcm6345_reset_probe, 127 .driver = { 128 .name = "bcm6345-reset", 129 .of_match_table = bcm6345_reset_of_match, 130 .suppress_bind_attrs = true, 131 }, 132 }; 133 builtin_platform_driver(bcm6345_reset_driver); 134