1 // SPDX-License-Identifier: GPL-2.0+ 2 3 #include <linux/module.h> 4 #include <linux/regmap.h> 5 6 #include "realtek.h" 7 #include "rtl83xx.h" 8 9 /** 10 * rtl83xx_lock() - Locks the mutex used by regmaps 11 * @ctx: realtek_priv pointer 12 * 13 * This function is passed to regmap to be used as the lock function. 14 * It is also used externally to block regmap before executing multiple 15 * operations that must happen in sequence (which will use 16 * realtek_priv.map_nolock instead). 17 * 18 * Context: Can sleep. Holds priv->map_lock lock. 19 * Return: nothing 20 */ 21 void rtl83xx_lock(void *ctx) 22 { 23 struct realtek_priv *priv = ctx; 24 25 mutex_lock(&priv->map_lock); 26 } 27 EXPORT_SYMBOL_NS_GPL(rtl83xx_lock, REALTEK_DSA); 28 29 /** 30 * rtl83xx_unlock() - Unlocks the mutex used by regmaps 31 * @ctx: realtek_priv pointer 32 * 33 * This function unlocks the lock acquired by rtl83xx_lock. 34 * 35 * Context: Releases priv->map_lock lock. 36 * Return: nothing 37 */ 38 void rtl83xx_unlock(void *ctx) 39 { 40 struct realtek_priv *priv = ctx; 41 42 mutex_unlock(&priv->map_lock); 43 } 44 EXPORT_SYMBOL_NS_GPL(rtl83xx_unlock, REALTEK_DSA); 45 46 /** 47 * rtl83xx_probe() - probe a Realtek switch 48 * @dev: the device being probed 49 * @interface_info: specific management interface info. 50 * 51 * This function initializes realtek_priv and reads data from the device tree 52 * node. The switch is hard resetted if a method is provided. 53 * 54 * Context: Can sleep. 55 * Return: Pointer to the realtek_priv or ERR_PTR() in case of failure. 56 * 57 * The realtek_priv pointer does not need to be freed as it is controlled by 58 * devres. 59 */ 60 struct realtek_priv * 61 rtl83xx_probe(struct device *dev, 62 const struct realtek_interface_info *interface_info) 63 { 64 const struct realtek_variant *var; 65 struct realtek_priv *priv; 66 struct regmap_config rc = { 67 .reg_bits = 10, /* A4..A0 R4..R0 */ 68 .val_bits = 16, 69 .reg_stride = 1, 70 .max_register = 0xffff, 71 .reg_format_endian = REGMAP_ENDIAN_BIG, 72 .reg_read = interface_info->reg_read, 73 .reg_write = interface_info->reg_write, 74 .cache_type = REGCACHE_NONE, 75 .lock = rtl83xx_lock, 76 .unlock = rtl83xx_unlock, 77 }; 78 int ret; 79 80 var = of_device_get_match_data(dev); 81 if (!var) 82 return ERR_PTR(-EINVAL); 83 84 priv = devm_kzalloc(dev, size_add(sizeof(*priv), var->chip_data_sz), 85 GFP_KERNEL); 86 if (!priv) 87 return ERR_PTR(-ENOMEM); 88 89 mutex_init(&priv->map_lock); 90 91 rc.lock_arg = priv; 92 priv->map = devm_regmap_init(dev, NULL, priv, &rc); 93 if (IS_ERR(priv->map)) { 94 ret = PTR_ERR(priv->map); 95 dev_err(dev, "regmap init failed: %d\n", ret); 96 return ERR_PTR(ret); 97 } 98 99 rc.disable_locking = true; 100 priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); 101 if (IS_ERR(priv->map_nolock)) { 102 ret = PTR_ERR(priv->map_nolock); 103 dev_err(dev, "regmap init failed: %d\n", ret); 104 return ERR_PTR(ret); 105 } 106 107 /* Link forward and backward */ 108 priv->dev = dev; 109 priv->variant = var; 110 priv->ops = var->ops; 111 priv->chip_data = (void *)priv + sizeof(*priv); 112 113 spin_lock_init(&priv->lock); 114 115 priv->leds_disabled = of_property_read_bool(dev->of_node, 116 "realtek,disable-leds"); 117 118 /* TODO: if power is software controlled, set up any regulators here */ 119 priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 120 if (IS_ERR(priv->reset)) { 121 dev_err(dev, "failed to get RESET GPIO\n"); 122 return ERR_CAST(priv->reset); 123 } 124 125 dev_set_drvdata(dev, priv); 126 127 if (priv->reset) { 128 gpiod_set_value(priv->reset, 1); 129 dev_dbg(dev, "asserted RESET\n"); 130 msleep(REALTEK_HW_STOP_DELAY); 131 gpiod_set_value(priv->reset, 0); 132 msleep(REALTEK_HW_START_DELAY); 133 dev_dbg(dev, "deasserted RESET\n"); 134 } 135 136 return priv; 137 } 138 EXPORT_SYMBOL_NS_GPL(rtl83xx_probe, REALTEK_DSA); 139 140 /** 141 * rtl83xx_register_switch() - detects and register a switch 142 * @priv: realtek_priv pointer 143 * 144 * This function first checks the switch chip ID and register a DSA 145 * switch. 146 * 147 * Context: Can sleep. Takes and releases priv->map_lock. 148 * Return: 0 on success, negative value for failure. 149 */ 150 int rtl83xx_register_switch(struct realtek_priv *priv) 151 { 152 struct dsa_switch *ds; 153 int ret; 154 155 ret = priv->ops->detect(priv); 156 if (ret) { 157 dev_err_probe(priv->dev, ret, "unable to detect switch\n"); 158 return ret; 159 } 160 161 ds = devm_kzalloc(priv->dev, sizeof(*ds), GFP_KERNEL); 162 if (!ds) 163 return -ENOMEM; 164 165 ds->priv = priv; 166 ds->dev = priv->dev; 167 ds->ops = priv->ds_ops; 168 ds->num_ports = priv->num_ports; 169 priv->ds = ds; 170 171 ret = dsa_register_switch(ds); 172 if (ret) { 173 dev_err_probe(priv->dev, ret, "unable to register switch\n"); 174 return ret; 175 } 176 177 return 0; 178 } 179 EXPORT_SYMBOL_NS_GPL(rtl83xx_register_switch, REALTEK_DSA); 180 181 /** 182 * rtl83xx_unregister_switch() - unregister a switch 183 * @priv: realtek_priv pointer 184 * 185 * This function unregister a DSA switch. 186 * 187 * Context: Can sleep. 188 * Return: Nothing. 189 */ 190 void rtl83xx_unregister_switch(struct realtek_priv *priv) 191 { 192 dsa_unregister_switch(priv->ds); 193 } 194 EXPORT_SYMBOL_NS_GPL(rtl83xx_unregister_switch, REALTEK_DSA); 195 196 /** 197 * rtl83xx_shutdown() - shutdown a switch 198 * @priv: realtek_priv pointer 199 * 200 * This function shuts down the DSA switch and cleans the platform driver data, 201 * to prevent realtek_{smi,mdio}_remove() from running afterwards, which is 202 * possible if the parent bus implements its own .shutdown() as .remove(). 203 * 204 * Context: Can sleep. 205 * Return: Nothing. 206 */ 207 void rtl83xx_shutdown(struct realtek_priv *priv) 208 { 209 dsa_switch_shutdown(priv->ds); 210 211 dev_set_drvdata(priv->dev, NULL); 212 } 213 EXPORT_SYMBOL_NS_GPL(rtl83xx_shutdown, REALTEK_DSA); 214 215 /** 216 * rtl83xx_remove() - Cleanup a realtek switch driver 217 * @priv: realtek_priv pointer 218 * 219 * If a method is provided, this function asserts the hard reset of the switch 220 * in order to avoid leaking traffic when the driver is gone. 221 * 222 * Context: Might sleep if priv->gdev->chip->can_sleep. 223 * Return: nothing 224 */ 225 void rtl83xx_remove(struct realtek_priv *priv) 226 { 227 /* leave the device reset asserted */ 228 if (priv->reset) 229 gpiod_set_value(priv->reset, 1); 230 } 231 EXPORT_SYMBOL_NS_GPL(rtl83xx_remove, REALTEK_DSA); 232 233 MODULE_AUTHOR("Luiz Angelo Daros de Luca <luizluca@gmail.com>"); 234 MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>"); 235 MODULE_DESCRIPTION("Realtek DSA switches common module"); 236 MODULE_LICENSE("GPL"); 237