162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2013 John Crispin <blogic@openwrt.org> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/device.h> 862306a36Sopenharmony_ci#include <linux/io.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 1362306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 1462306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 1562306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 1662306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1762306a36Sopenharmony_ci#include <linux/pinctrl/machine.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <asm/mach-ralink/ralink_regs.h> 2062306a36Sopenharmony_ci#include <asm/mach-ralink/mt7620.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "pinctrl-mtmips.h" 2362306a36Sopenharmony_ci#include "../core.h" 2462306a36Sopenharmony_ci#include "../pinctrl-utils.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define SYSC_REG_GPIO_MODE 0x60 2762306a36Sopenharmony_ci#define SYSC_REG_GPIO_MODE2 0x64 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistruct mtmips_priv { 3062306a36Sopenharmony_ci struct device *dev; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci struct pinctrl_pin_desc *pads; 3362306a36Sopenharmony_ci struct pinctrl_desc *desc; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci struct mtmips_pmx_func **func; 3662306a36Sopenharmony_ci int func_count; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci struct mtmips_pmx_group *groups; 3962306a36Sopenharmony_ci const char **group_names; 4062306a36Sopenharmony_ci int group_count; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci u8 *gpio; 4362306a36Sopenharmony_ci int max_pins; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int mtmips_get_group_count(struct pinctrl_dev *pctrldev) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return p->group_count; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const char *mtmips_get_group_name(struct pinctrl_dev *pctrldev, 5462306a36Sopenharmony_ci unsigned int group) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return (group >= p->group_count) ? NULL : p->group_names[group]; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int mtmips_get_group_pins(struct pinctrl_dev *pctrldev, 6262306a36Sopenharmony_ci unsigned int group, 6362306a36Sopenharmony_ci const unsigned int **pins, 6462306a36Sopenharmony_ci unsigned int *num_pins) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (group >= p->group_count) 6962306a36Sopenharmony_ci return -EINVAL; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci *pins = p->groups[group].func[0].pins; 7262306a36Sopenharmony_ci *num_pins = p->groups[group].func[0].pin_count; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return 0; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct pinctrl_ops mtmips_pctrl_ops = { 7862306a36Sopenharmony_ci .get_groups_count = mtmips_get_group_count, 7962306a36Sopenharmony_ci .get_group_name = mtmips_get_group_name, 8062306a36Sopenharmony_ci .get_group_pins = mtmips_get_group_pins, 8162306a36Sopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_all, 8262306a36Sopenharmony_ci .dt_free_map = pinconf_generic_dt_free_map, 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int mtmips_pmx_func_count(struct pinctrl_dev *pctrldev) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci return p->func_count; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const char *mtmips_pmx_func_name(struct pinctrl_dev *pctrldev, 9362306a36Sopenharmony_ci unsigned int func) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return p->func[func]->name; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int mtmips_pmx_group_get_groups(struct pinctrl_dev *pctrldev, 10162306a36Sopenharmony_ci unsigned int func, 10262306a36Sopenharmony_ci const char * const **groups, 10362306a36Sopenharmony_ci unsigned int * const num_groups) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (p->func[func]->group_count == 1) 10862306a36Sopenharmony_ci *groups = &p->group_names[p->func[func]->groups[0]]; 10962306a36Sopenharmony_ci else 11062306a36Sopenharmony_ci *groups = p->group_names; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci *num_groups = p->func[func]->group_count; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic int mtmips_pmx_group_enable(struct pinctrl_dev *pctrldev, 11862306a36Sopenharmony_ci unsigned int func, unsigned int group) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); 12162306a36Sopenharmony_ci u32 mode = 0; 12262306a36Sopenharmony_ci u32 reg = SYSC_REG_GPIO_MODE; 12362306a36Sopenharmony_ci int i; 12462306a36Sopenharmony_ci int shift; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* dont allow double use */ 12762306a36Sopenharmony_ci if (p->groups[group].enabled) { 12862306a36Sopenharmony_ci dev_err(p->dev, "%s is already enabled\n", 12962306a36Sopenharmony_ci p->groups[group].name); 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci p->groups[group].enabled = 1; 13462306a36Sopenharmony_ci p->func[func]->enabled = 1; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci shift = p->groups[group].shift; 13762306a36Sopenharmony_ci if (shift >= 32) { 13862306a36Sopenharmony_ci shift -= 32; 13962306a36Sopenharmony_ci reg = SYSC_REG_GPIO_MODE2; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci mode = rt_sysc_r32(reg); 14262306a36Sopenharmony_ci mode &= ~(p->groups[group].mask << shift); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* mark the pins as gpio */ 14562306a36Sopenharmony_ci for (i = 0; i < p->groups[group].func[0].pin_count; i++) 14662306a36Sopenharmony_ci p->gpio[p->groups[group].func[0].pins[i]] = 1; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* function 0 is gpio and needs special handling */ 14962306a36Sopenharmony_ci if (func == 0) { 15062306a36Sopenharmony_ci mode |= p->groups[group].gpio << shift; 15162306a36Sopenharmony_ci } else { 15262306a36Sopenharmony_ci for (i = 0; i < p->func[func]->pin_count; i++) 15362306a36Sopenharmony_ci p->gpio[p->func[func]->pins[i]] = 0; 15462306a36Sopenharmony_ci mode |= p->func[func]->value << shift; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci rt_sysc_w32(mode, reg); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int mtmips_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev, 16262306a36Sopenharmony_ci struct pinctrl_gpio_range *range, 16362306a36Sopenharmony_ci unsigned int pin) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct mtmips_priv *p = pinctrl_dev_get_drvdata(pctrldev); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (!p->gpio[pin]) { 16862306a36Sopenharmony_ci dev_err(p->dev, "pin %d is not set to gpio mux\n", pin); 16962306a36Sopenharmony_ci return -EINVAL; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic const struct pinmux_ops mtmips_pmx_group_ops = { 17662306a36Sopenharmony_ci .get_functions_count = mtmips_pmx_func_count, 17762306a36Sopenharmony_ci .get_function_name = mtmips_pmx_func_name, 17862306a36Sopenharmony_ci .get_function_groups = mtmips_pmx_group_get_groups, 17962306a36Sopenharmony_ci .set_mux = mtmips_pmx_group_enable, 18062306a36Sopenharmony_ci .gpio_request_enable = mtmips_pmx_group_gpio_request_enable, 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic struct pinctrl_desc mtmips_pctrl_desc = { 18462306a36Sopenharmony_ci .owner = THIS_MODULE, 18562306a36Sopenharmony_ci .name = "mtmips-pinctrl", 18662306a36Sopenharmony_ci .pctlops = &mtmips_pctrl_ops, 18762306a36Sopenharmony_ci .pmxops = &mtmips_pmx_group_ops, 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic struct mtmips_pmx_func gpio_func = { 19162306a36Sopenharmony_ci .name = "gpio", 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int mtmips_pinctrl_index(struct mtmips_priv *p) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct mtmips_pmx_group *mux = p->groups; 19762306a36Sopenharmony_ci int i, j, c = 0; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* count the mux functions */ 20062306a36Sopenharmony_ci while (mux->name) { 20162306a36Sopenharmony_ci p->group_count++; 20262306a36Sopenharmony_ci mux++; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* allocate the group names array needed by the gpio function */ 20662306a36Sopenharmony_ci p->group_names = devm_kcalloc(p->dev, p->group_count, 20762306a36Sopenharmony_ci sizeof(char *), GFP_KERNEL); 20862306a36Sopenharmony_ci if (!p->group_names) 20962306a36Sopenharmony_ci return -ENOMEM; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci for (i = 0; i < p->group_count; i++) { 21262306a36Sopenharmony_ci p->group_names[i] = p->groups[i].name; 21362306a36Sopenharmony_ci p->func_count += p->groups[i].func_count; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* we have a dummy function[0] for gpio */ 21762306a36Sopenharmony_ci p->func_count++; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* allocate our function and group mapping index buffers */ 22062306a36Sopenharmony_ci p->func = devm_kcalloc(p->dev, p->func_count, 22162306a36Sopenharmony_ci sizeof(*p->func), GFP_KERNEL); 22262306a36Sopenharmony_ci gpio_func.groups = devm_kcalloc(p->dev, p->group_count, sizeof(int), 22362306a36Sopenharmony_ci GFP_KERNEL); 22462306a36Sopenharmony_ci if (!p->func || !gpio_func.groups) 22562306a36Sopenharmony_ci return -ENOMEM; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* add a backpointer to the function so it knows its group */ 22862306a36Sopenharmony_ci gpio_func.group_count = p->group_count; 22962306a36Sopenharmony_ci for (i = 0; i < gpio_func.group_count; i++) 23062306a36Sopenharmony_ci gpio_func.groups[i] = i; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci p->func[c] = &gpio_func; 23362306a36Sopenharmony_ci c++; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* add remaining functions */ 23662306a36Sopenharmony_ci for (i = 0; i < p->group_count; i++) { 23762306a36Sopenharmony_ci for (j = 0; j < p->groups[i].func_count; j++) { 23862306a36Sopenharmony_ci p->func[c] = &p->groups[i].func[j]; 23962306a36Sopenharmony_ci p->func[c]->groups = devm_kzalloc(p->dev, sizeof(int), 24062306a36Sopenharmony_ci GFP_KERNEL); 24162306a36Sopenharmony_ci if (!p->func[c]->groups) 24262306a36Sopenharmony_ci return -ENOMEM; 24362306a36Sopenharmony_ci p->func[c]->groups[0] = i; 24462306a36Sopenharmony_ci p->func[c]->group_count = 1; 24562306a36Sopenharmony_ci c++; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int mtmips_pinctrl_pins(struct mtmips_priv *p) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci int i, j; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* 25662306a36Sopenharmony_ci * loop over the functions and initialize the pins array. 25762306a36Sopenharmony_ci * also work out the highest pin used. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci for (i = 0; i < p->func_count; i++) { 26062306a36Sopenharmony_ci int pin; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (!p->func[i]->pin_count) 26362306a36Sopenharmony_ci continue; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci p->func[i]->pins = devm_kcalloc(p->dev, 26662306a36Sopenharmony_ci p->func[i]->pin_count, 26762306a36Sopenharmony_ci sizeof(int), 26862306a36Sopenharmony_ci GFP_KERNEL); 26962306a36Sopenharmony_ci if (!p->func[i]->pins) 27062306a36Sopenharmony_ci return -ENOMEM; 27162306a36Sopenharmony_ci for (j = 0; j < p->func[i]->pin_count; j++) 27262306a36Sopenharmony_ci p->func[i]->pins[j] = p->func[i]->pin_first + j; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci pin = p->func[i]->pin_first + p->func[i]->pin_count; 27562306a36Sopenharmony_ci if (pin > p->max_pins) 27662306a36Sopenharmony_ci p->max_pins = pin; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* the buffer that tells us which pins are gpio */ 28062306a36Sopenharmony_ci p->gpio = devm_kcalloc(p->dev, p->max_pins, sizeof(u8), GFP_KERNEL); 28162306a36Sopenharmony_ci /* the pads needed to tell pinctrl about our pins */ 28262306a36Sopenharmony_ci p->pads = devm_kcalloc(p->dev, p->max_pins, 28362306a36Sopenharmony_ci sizeof(struct pinctrl_pin_desc), GFP_KERNEL); 28462306a36Sopenharmony_ci if (!p->pads || !p->gpio) 28562306a36Sopenharmony_ci return -ENOMEM; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci memset(p->gpio, 1, sizeof(u8) * p->max_pins); 28862306a36Sopenharmony_ci for (i = 0; i < p->func_count; i++) { 28962306a36Sopenharmony_ci if (!p->func[i]->pin_count) 29062306a36Sopenharmony_ci continue; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci for (j = 0; j < p->func[i]->pin_count; j++) 29362306a36Sopenharmony_ci p->gpio[p->func[i]->pins[j]] = 0; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* pin 0 is always a gpio */ 29762306a36Sopenharmony_ci p->gpio[0] = 1; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* set the pads */ 30062306a36Sopenharmony_ci for (i = 0; i < p->max_pins; i++) { 30162306a36Sopenharmony_ci /* strlen("ioXY") + 1 = 5 */ 30262306a36Sopenharmony_ci char *name = devm_kzalloc(p->dev, 5, GFP_KERNEL); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!name) 30562306a36Sopenharmony_ci return -ENOMEM; 30662306a36Sopenharmony_ci snprintf(name, 5, "io%d", i); 30762306a36Sopenharmony_ci p->pads[i].number = i; 30862306a36Sopenharmony_ci p->pads[i].name = name; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci p->desc->pins = p->pads; 31162306a36Sopenharmony_ci p->desc->npins = p->max_pins; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci return 0; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ciint mtmips_pinctrl_init(struct platform_device *pdev, 31762306a36Sopenharmony_ci struct mtmips_pmx_group *data) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct mtmips_priv *p; 32062306a36Sopenharmony_ci struct pinctrl_dev *dev; 32162306a36Sopenharmony_ci int err; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (!data) 32462306a36Sopenharmony_ci return -ENOTSUPP; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci /* setup the private data */ 32762306a36Sopenharmony_ci p = devm_kzalloc(&pdev->dev, sizeof(struct mtmips_priv), GFP_KERNEL); 32862306a36Sopenharmony_ci if (!p) 32962306a36Sopenharmony_ci return -ENOMEM; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci p->dev = &pdev->dev; 33262306a36Sopenharmony_ci p->desc = &mtmips_pctrl_desc; 33362306a36Sopenharmony_ci p->groups = data; 33462306a36Sopenharmony_ci platform_set_drvdata(pdev, p); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* init the device */ 33762306a36Sopenharmony_ci err = mtmips_pinctrl_index(p); 33862306a36Sopenharmony_ci if (err) { 33962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to load index\n"); 34062306a36Sopenharmony_ci return err; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci err = mtmips_pinctrl_pins(p); 34462306a36Sopenharmony_ci if (err) { 34562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to load pins\n"); 34662306a36Sopenharmony_ci return err; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci dev = pinctrl_register(p->desc, &pdev->dev, p); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(dev); 35162306a36Sopenharmony_ci} 352