1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Sophgo CV18XX SoCs pinctrl driver. 4 * 5 * Copyright (C) 2024 Inochi Amaoto <inochiama@outlook.com> 6 * 7 */ 8 9 #include <linux/bitfield.h> 10 #include <linux/export.h> 11 #include <linux/io.h> 12 #include <linux/of.h> 13 #include <linux/platform_device.h> 14 #include <linux/bsearch.h> 15 #include <linux/seq_file.h> 16 #include <linux/spinlock.h> 17 18 #include <linux/pinctrl/pinconf-generic.h> 19 #include <linux/pinctrl/pinconf.h> 20 #include <linux/pinctrl/pinctrl.h> 21 #include <linux/pinctrl/pinmux.h> 22 23 #include <dt-bindings/pinctrl/pinctrl-cv18xx.h> 24 25 #include "../pinctrl-utils.h" 26 #include "../pinmux.h" 27 #include "pinctrl-cv18xx.h" 28 29 struct cv1800_priv { 30 u32 *power_cfg; 31 void __iomem *regs[2]; 32 }; 33 34 static unsigned int cv1800_dt_get_pin_mux(u32 value) 35 { 36 return (value >> 16) & GENMASK(7, 0); 37 } 38 39 static unsigned int cv1800_dt_get_pin_mux2(u32 value) 40 { 41 return (value >> 24) & GENMASK(7, 0); 42 } 43 44 #define cv1800_pinctrl_get_component_addr(pctrl, _comp) \ 45 ((pctrl)->regs[(_comp)->area] + (_comp)->offset) 46 47 static int cv1800_set_power_cfg(struct sophgo_pinctrl *pctrl, 48 u8 domain, u32 cfg) 49 { 50 struct cv1800_priv *priv = pctrl->priv_ctrl; 51 52 if (domain >= pctrl->data->npds) 53 return -ENOTSUPP; 54 55 if (priv->power_cfg[domain] && priv->power_cfg[domain] != cfg) 56 return -EINVAL; 57 58 priv->power_cfg[domain] = cfg; 59 60 return 0; 61 } 62 63 static int cv1800_get_power_cfg(struct sophgo_pinctrl *pctrl, 64 u8 domain) 65 { 66 struct cv1800_priv *priv = pctrl->priv_ctrl; 67 68 return priv->power_cfg[domain]; 69 } 70 71 #define PIN_BGA_ID_OFFSET 8 72 #define PIN_BGA_ID_MASK 0xff 73 74 static const char *const io_type_desc[] = { 75 "1V8", 76 "18OD33", 77 "AUDIO", 78 "ETH" 79 }; 80 81 static const char *cv1800_get_power_cfg_desc(struct sophgo_pinctrl *pctrl, 82 u8 domain) 83 { 84 return pctrl->data->pdnames[domain]; 85 } 86 87 static void cv1800_pctrl_dbg_show(struct pinctrl_dev *pctldev, 88 struct seq_file *seq, unsigned int pin_id) 89 { 90 struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 91 struct cv1800_priv *priv = pctrl->priv_ctrl; 92 const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); 93 const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); 94 enum cv1800_pin_io_type type = cv1800_pin_io_type(pin); 95 u32 pin_hwid = pin->pin.id; 96 u32 value; 97 void __iomem *reg; 98 99 if (pin_hwid >> PIN_BGA_ID_OFFSET) 100 seq_printf(seq, "pos: %c%u ", 101 'A' + (pin_hwid >> PIN_BGA_ID_OFFSET) - 1, 102 pin_hwid & PIN_BGA_ID_MASK); 103 else 104 seq_printf(seq, "pos: %u ", pin_hwid); 105 106 seq_printf(seq, "power-domain: %s ", 107 cv1800_get_power_cfg_desc(pctrl, pin->power_domain)); 108 seq_printf(seq, "type: %s ", io_type_desc[type]); 109 110 reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux); 111 value = readl(reg); 112 seq_printf(seq, "mux: 0x%08x ", value); 113 114 if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) { 115 reg = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); 116 value = readl(reg); 117 seq_printf(seq, "mux2: 0x%08x ", value); 118 } 119 120 if (type == IO_TYPE_1V8_ONLY || type == IO_TYPE_1V8_OR_3V3) { 121 reg = cv1800_pinctrl_get_component_addr(priv, &pin->conf); 122 value = readl(reg); 123 seq_printf(seq, "conf: 0x%08x ", value); 124 } 125 } 126 127 static int cv1800_verify_pinmux_config(const struct sophgo_pin_mux_config *config) 128 { 129 struct cv1800_pin *pin = sophgo_to_cv1800_pin(config->pin); 130 unsigned int mux = cv1800_dt_get_pin_mux(config->config); 131 unsigned int mux2 = cv1800_dt_get_pin_mux2(config->config); 132 133 if (mux > pin->mux.max) 134 return -EINVAL; 135 136 if (pin->pin.flags & CV1800_PIN_HAVE_MUX2) { 137 if (mux != pin->mux2.pfunc) 138 return -EINVAL; 139 140 if (mux2 > pin->mux2.max) 141 return -EINVAL; 142 } else { 143 if (mux2 != PIN_MUX_INVALD) 144 return -ENOTSUPP; 145 } 146 147 return 0; 148 } 149 150 static int cv1800_verify_pin_group(const struct sophgo_pin_mux_config *mux, 151 unsigned int npins) 152 { 153 struct cv1800_pin *pin; 154 enum cv1800_pin_io_type type; 155 u8 power_domain; 156 int i; 157 158 if (npins == 1) 159 return 0; 160 161 pin = sophgo_to_cv1800_pin(mux[0].pin); 162 type = cv1800_pin_io_type(pin); 163 power_domain = pin->power_domain; 164 165 for (i = 0; i < npins; i++) { 166 pin = sophgo_to_cv1800_pin(mux[i].pin); 167 168 if (type != cv1800_pin_io_type(pin) || 169 power_domain != pin->power_domain) 170 return -ENOTSUPP; 171 } 172 173 return 0; 174 } 175 176 static int cv1800_dt_node_to_map_post(struct device_node *cur, 177 struct sophgo_pinctrl *pctrl, 178 struct sophgo_pin_mux_config *pinmuxs, 179 unsigned int npins) 180 { 181 const struct cv1800_pin *pin = sophgo_to_cv1800_pin(pinmuxs[0].pin); 182 u32 power; 183 int ret; 184 185 ret = of_property_read_u32(cur, "power-source", &power); 186 if (ret) 187 return ret; 188 189 if (!(power == PIN_POWER_STATE_3V3 || power == PIN_POWER_STATE_1V8)) 190 return -ENOTSUPP; 191 192 return cv1800_set_power_cfg(pctrl, pin->power_domain, power); 193 } 194 195 const struct pinctrl_ops cv1800_pctrl_ops = { 196 .get_groups_count = pinctrl_generic_get_group_count, 197 .get_group_name = pinctrl_generic_get_group_name, 198 .get_group_pins = pinctrl_generic_get_group_pins, 199 .pin_dbg_show = cv1800_pctrl_dbg_show, 200 .dt_node_to_map = sophgo_pctrl_dt_node_to_map, 201 .dt_free_map = pinctrl_utils_free_map, 202 }; 203 EXPORT_SYMBOL_GPL(cv1800_pctrl_ops); 204 205 static void cv1800_set_pinmux_config(struct sophgo_pinctrl *pctrl, 206 const struct sophgo_pin *sp, u32 config) 207 { 208 const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); 209 struct cv1800_priv *priv = pctrl->priv_ctrl; 210 void __iomem *reg_mux; 211 void __iomem *reg_mux2; 212 u32 mux; 213 u32 mux2; 214 215 reg_mux = cv1800_pinctrl_get_component_addr(priv, &pin->mux); 216 reg_mux2 = cv1800_pinctrl_get_component_addr(priv, &pin->mux2); 217 mux = cv1800_dt_get_pin_mux(config); 218 mux2 = cv1800_dt_get_pin_mux2(config); 219 220 writel_relaxed(mux, reg_mux); 221 if (mux2 != PIN_MUX_INVALD) 222 writel_relaxed(mux2, reg_mux2); 223 } 224 225 const struct pinmux_ops cv1800_pmx_ops = { 226 .get_functions_count = pinmux_generic_get_function_count, 227 .get_function_name = pinmux_generic_get_function_name, 228 .get_function_groups = pinmux_generic_get_function_groups, 229 .set_mux = sophgo_pmx_set_mux, 230 .strict = true, 231 }; 232 EXPORT_SYMBOL_GPL(cv1800_pmx_ops); 233 234 #define PIN_IO_PULLUP BIT(2) 235 #define PIN_IO_PULLDOWN BIT(3) 236 #define PIN_IO_DRIVE GENMASK(7, 5) 237 #define PIN_IO_SCHMITT GENMASK(9, 8) 238 #define PIN_IO_BUS_HOLD BIT(10) 239 #define PIN_IO_OUT_FAST_SLEW BIT(11) 240 241 static int cv1800_pconf_get(struct pinctrl_dev *pctldev, 242 unsigned int pin_id, unsigned long *config) 243 { 244 struct sophgo_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); 245 struct cv1800_priv *priv = pctrl->priv_ctrl; 246 int param = pinconf_to_config_param(*config); 247 const struct sophgo_pin *sp = sophgo_get_pin(pctrl, pin_id); 248 const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); 249 enum cv1800_pin_io_type type; 250 u32 value; 251 u32 arg; 252 bool enabled; 253 int ret; 254 255 if (!pin) 256 return -EINVAL; 257 258 type = cv1800_pin_io_type(pin); 259 if (type == IO_TYPE_ETH || type == IO_TYPE_AUDIO) 260 return -ENOTSUPP; 261 262 value = readl(cv1800_pinctrl_get_component_addr(priv, &pin->conf)); 263 264 switch (param) { 265 case PIN_CONFIG_BIAS_PULL_DOWN: 266 enabled = FIELD_GET(PIN_IO_PULLDOWN, value); 267 arg = sophgo_pinctrl_typical_pull_down(pctrl, sp, priv->power_cfg); 268 break; 269 case PIN_CONFIG_BIAS_PULL_UP: 270 enabled = FIELD_GET(PIN_IO_PULLUP, value); 271 arg = sophgo_pinctrl_typical_pull_up(pctrl, sp, priv->power_cfg); 272 break; 273 case PIN_CONFIG_DRIVE_STRENGTH_UA: 274 enabled = true; 275 arg = FIELD_GET(PIN_IO_DRIVE, value); 276 ret = sophgo_pinctrl_reg2oc(pctrl, sp, priv->power_cfg, arg); 277 if (ret < 0) 278 return ret; 279 arg = ret; 280 break; 281 case PIN_CONFIG_INPUT_SCHMITT_UV: 282 arg = FIELD_GET(PIN_IO_SCHMITT, value); 283 ret = sophgo_pinctrl_reg2schmitt(pctrl, sp, priv->power_cfg, arg); 284 if (ret < 0) 285 return ret; 286 arg = ret; 287 enabled = arg != 0; 288 break; 289 case PIN_CONFIG_POWER_SOURCE: 290 enabled = true; 291 arg = cv1800_get_power_cfg(pctrl, pin->power_domain); 292 break; 293 case PIN_CONFIG_SLEW_RATE: 294 enabled = true; 295 arg = FIELD_GET(PIN_IO_OUT_FAST_SLEW, value); 296 break; 297 case PIN_CONFIG_BIAS_BUS_HOLD: 298 arg = FIELD_GET(PIN_IO_BUS_HOLD, value); 299 enabled = arg != 0; 300 break; 301 default: 302 return -ENOTSUPP; 303 } 304 305 *config = pinconf_to_config_packed(param, arg); 306 307 return enabled ? 0 : -EINVAL; 308 } 309 310 static int cv1800_pinconf_compute_config(struct sophgo_pinctrl *pctrl, 311 const struct sophgo_pin *sp, 312 unsigned long *configs, 313 unsigned int num_configs, 314 u32 *value, u32 *mask) 315 { 316 struct cv1800_priv *priv = pctrl->priv_ctrl; 317 const struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); 318 int i; 319 u32 v = 0, m = 0; 320 enum cv1800_pin_io_type type; 321 int ret; 322 323 if (!pin) 324 return -EINVAL; 325 326 type = cv1800_pin_io_type(pin); 327 if (type == IO_TYPE_ETH || type == IO_TYPE_AUDIO) 328 return -ENOTSUPP; 329 330 for (i = 0; i < num_configs; i++) { 331 int param = pinconf_to_config_param(configs[i]); 332 u32 arg = pinconf_to_config_argument(configs[i]); 333 334 switch (param) { 335 case PIN_CONFIG_BIAS_PULL_DOWN: 336 v &= ~PIN_IO_PULLDOWN; 337 v |= FIELD_PREP(PIN_IO_PULLDOWN, arg); 338 m |= PIN_IO_PULLDOWN; 339 break; 340 case PIN_CONFIG_BIAS_PULL_UP: 341 v &= ~PIN_IO_PULLUP; 342 v |= FIELD_PREP(PIN_IO_PULLUP, arg); 343 m |= PIN_IO_PULLUP; 344 break; 345 case PIN_CONFIG_DRIVE_STRENGTH_UA: 346 ret = sophgo_pinctrl_oc2reg(pctrl, sp, 347 priv->power_cfg, arg); 348 if (ret < 0) 349 return ret; 350 v &= ~PIN_IO_DRIVE; 351 v |= FIELD_PREP(PIN_IO_DRIVE, ret); 352 m |= PIN_IO_DRIVE; 353 break; 354 case PIN_CONFIG_INPUT_SCHMITT_UV: 355 ret = sophgo_pinctrl_schmitt2reg(pctrl, sp, 356 priv->power_cfg, arg); 357 if (ret < 0) 358 return ret; 359 v &= ~PIN_IO_SCHMITT; 360 v |= FIELD_PREP(PIN_IO_SCHMITT, ret); 361 m |= PIN_IO_SCHMITT; 362 break; 363 case PIN_CONFIG_POWER_SOURCE: 364 /* Ignore power source as it is always fixed */ 365 break; 366 case PIN_CONFIG_SLEW_RATE: 367 v &= ~PIN_IO_OUT_FAST_SLEW; 368 v |= FIELD_PREP(PIN_IO_OUT_FAST_SLEW, arg); 369 m |= PIN_IO_OUT_FAST_SLEW; 370 break; 371 case PIN_CONFIG_BIAS_BUS_HOLD: 372 v &= ~PIN_IO_BUS_HOLD; 373 v |= FIELD_PREP(PIN_IO_BUS_HOLD, arg); 374 m |= PIN_IO_BUS_HOLD; 375 break; 376 default: 377 return -ENOTSUPP; 378 } 379 } 380 381 *value = v; 382 *mask = m; 383 384 return 0; 385 } 386 387 static int cv1800_set_pinconf_config(struct sophgo_pinctrl *pctrl, 388 const struct sophgo_pin *sp, 389 u32 value, u32 mask) 390 { 391 struct cv1800_priv *priv = pctrl->priv_ctrl; 392 struct cv1800_pin *pin = sophgo_to_cv1800_pin(sp); 393 void __iomem *addr; 394 u32 reg; 395 396 addr = cv1800_pinctrl_get_component_addr(priv, &pin->conf); 397 398 reg = readl(addr); 399 reg &= ~mask; 400 reg |= value; 401 writel(reg, addr); 402 403 return 0; 404 } 405 406 const struct pinconf_ops cv1800_pconf_ops = { 407 .pin_config_get = cv1800_pconf_get, 408 .pin_config_set = sophgo_pconf_set, 409 .pin_config_group_set = sophgo_pconf_group_set, 410 .is_generic = true, 411 }; 412 EXPORT_SYMBOL_GPL(cv1800_pconf_ops); 413 414 static int cv1800_pinctrl_init(struct platform_device *pdev, 415 struct sophgo_pinctrl *pctrl) 416 { 417 const struct sophgo_pinctrl_data *pctrl_data = pctrl->data; 418 struct cv1800_priv *priv; 419 420 priv = devm_kzalloc(&pdev->dev, sizeof(struct cv1800_priv), GFP_KERNEL); 421 if (!priv) 422 return -ENOMEM; 423 424 priv->power_cfg = devm_kcalloc(&pdev->dev, pctrl_data->npds, 425 sizeof(u32), GFP_KERNEL); 426 if (!priv->power_cfg) 427 return -ENOMEM; 428 429 priv->regs[0] = devm_platform_ioremap_resource_byname(pdev, "sys"); 430 if (IS_ERR(priv->regs[0])) 431 return PTR_ERR(priv->regs[0]); 432 433 priv->regs[1] = devm_platform_ioremap_resource_byname(pdev, "rtc"); 434 if (IS_ERR(priv->regs[1])) 435 return PTR_ERR(priv->regs[1]); 436 437 pctrl->priv_ctrl = priv; 438 439 return 0; 440 } 441 442 const struct sophgo_cfg_ops cv1800_cfg_ops = { 443 .pctrl_init = cv1800_pinctrl_init, 444 .verify_pinmux_config = cv1800_verify_pinmux_config, 445 .verify_pin_group = cv1800_verify_pin_group, 446 .dt_node_to_map_post = cv1800_dt_node_to_map_post, 447 .compute_pinconf_config = cv1800_pinconf_compute_config, 448 .set_pinconf_config = cv1800_set_pinconf_config, 449 .set_pinmux_config = cv1800_set_pinmux_config, 450 }; 451 EXPORT_SYMBOL_GPL(cv1800_cfg_ops); 452