18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Marvell PXA2xx family pin control 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Robert Jarzmik 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bitops.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci#include <linux/of_address.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h> 148c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 158c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 168c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 178c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h" 228c2ecf20Sopenharmony_ci#include "pinctrl-pxa2xx.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int pxa2xx_pctrl_get_groups_count(struct pinctrl_dev *pctldev) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci return pctl->ngroups; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic const char *pxa2xx_pctrl_get_group_name(struct pinctrl_dev *pctldev, 328c2ecf20Sopenharmony_ci unsigned tgroup) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 358c2ecf20Sopenharmony_ci struct pxa_pinctrl_group *group = pctl->groups + tgroup; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci return group->name; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic int pxa2xx_pctrl_get_group_pins(struct pinctrl_dev *pctldev, 418c2ecf20Sopenharmony_ci unsigned tgroup, 428c2ecf20Sopenharmony_ci const unsigned **pins, 438c2ecf20Sopenharmony_ci unsigned *num_pins) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 468c2ecf20Sopenharmony_ci struct pxa_pinctrl_group *group = pctl->groups + tgroup; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci *pins = (unsigned *)&group->pin; 498c2ecf20Sopenharmony_ci *num_pins = 1; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const struct pinctrl_ops pxa2xx_pctl_ops = { 558c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 568c2ecf20Sopenharmony_ci .dt_node_to_map = pinconf_generic_dt_node_to_map_all, 578c2ecf20Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 588c2ecf20Sopenharmony_ci#endif 598c2ecf20Sopenharmony_ci .get_groups_count = pxa2xx_pctrl_get_groups_count, 608c2ecf20Sopenharmony_ci .get_group_name = pxa2xx_pctrl_get_group_name, 618c2ecf20Sopenharmony_ci .get_group_pins = pxa2xx_pctrl_get_group_pins, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic struct pxa_desc_function * 658c2ecf20Sopenharmony_cipxa_desc_by_func_group(struct pxa_pinctrl *pctl, const char *pin_name, 668c2ecf20Sopenharmony_ci const char *func_name) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci int i; 698c2ecf20Sopenharmony_ci struct pxa_desc_function *df; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci for (i = 0; i < pctl->npins; i++) { 728c2ecf20Sopenharmony_ci const struct pxa_desc_pin *pin = pctl->ppins + i; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (!strcmp(pin->pin.name, pin_name)) 758c2ecf20Sopenharmony_ci for (df = pin->functions; df->name; df++) 768c2ecf20Sopenharmony_ci if (!strcmp(df->name, func_name)) 778c2ecf20Sopenharmony_ci return df; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return NULL; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int pxa2xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, 848c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, 858c2ecf20Sopenharmony_ci unsigned pin, 868c2ecf20Sopenharmony_ci bool input) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 898c2ecf20Sopenharmony_ci unsigned long flags; 908c2ecf20Sopenharmony_ci uint32_t val; 918c2ecf20Sopenharmony_ci void __iomem *gpdr; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci gpdr = pctl->base_gpdr[pin / 32]; 948c2ecf20Sopenharmony_ci dev_dbg(pctl->dev, "set_direction(pin=%d): dir=%d\n", 958c2ecf20Sopenharmony_ci pin, !input); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci spin_lock_irqsave(&pctl->lock, flags); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci val = readl_relaxed(gpdr); 1008c2ecf20Sopenharmony_ci val = (val & ~BIT(pin % 32)) | (input ? 0 : BIT(pin % 32)); 1018c2ecf20Sopenharmony_ci writel_relaxed(val, gpdr); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pctl->lock, flags); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return 0; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic const char *pxa2xx_pmx_get_func_name(struct pinctrl_dev *pctldev, 1098c2ecf20Sopenharmony_ci unsigned function) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1128c2ecf20Sopenharmony_ci struct pxa_pinctrl_function *pf = pctl->functions + function; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return pf->name; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int pxa2xx_get_functions_count(struct pinctrl_dev *pctldev) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return pctl->nfuncs; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int pxa2xx_pmx_get_func_groups(struct pinctrl_dev *pctldev, 1258c2ecf20Sopenharmony_ci unsigned function, 1268c2ecf20Sopenharmony_ci const char * const **groups, 1278c2ecf20Sopenharmony_ci unsigned * const num_groups) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1308c2ecf20Sopenharmony_ci struct pxa_pinctrl_function *pf = pctl->functions + function; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci *groups = pf->groups; 1338c2ecf20Sopenharmony_ci *num_groups = pf->ngroups; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int pxa2xx_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned function, 1398c2ecf20Sopenharmony_ci unsigned tgroup) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1428c2ecf20Sopenharmony_ci struct pxa_pinctrl_group *group = pctl->groups + tgroup; 1438c2ecf20Sopenharmony_ci struct pxa_desc_function *df; 1448c2ecf20Sopenharmony_ci int pin, shift; 1458c2ecf20Sopenharmony_ci unsigned long flags; 1468c2ecf20Sopenharmony_ci void __iomem *gafr, *gpdr; 1478c2ecf20Sopenharmony_ci u32 val; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci df = pxa_desc_by_func_group(pctl, group->name, 1518c2ecf20Sopenharmony_ci (pctl->functions + function)->name); 1528c2ecf20Sopenharmony_ci if (!df) 1538c2ecf20Sopenharmony_ci return -EINVAL; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci pin = group->pin; 1568c2ecf20Sopenharmony_ci gafr = pctl->base_gafr[pin / 16]; 1578c2ecf20Sopenharmony_ci gpdr = pctl->base_gpdr[pin / 32]; 1588c2ecf20Sopenharmony_ci shift = (pin % 16) << 1; 1598c2ecf20Sopenharmony_ci dev_dbg(pctl->dev, "set_mux(pin=%d): af=%d dir=%d\n", 1608c2ecf20Sopenharmony_ci pin, df->muxval >> 1, df->muxval & 0x1); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci spin_lock_irqsave(&pctl->lock, flags); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci val = readl_relaxed(gafr); 1658c2ecf20Sopenharmony_ci val = (val & ~(0x3 << shift)) | ((df->muxval >> 1) << shift); 1668c2ecf20Sopenharmony_ci writel_relaxed(val, gafr); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci val = readl_relaxed(gpdr); 1698c2ecf20Sopenharmony_ci val = (val & ~BIT(pin % 32)) | ((df->muxval & 1) ? BIT(pin % 32) : 0); 1708c2ecf20Sopenharmony_ci writel_relaxed(val, gpdr); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pctl->lock, flags); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_cistatic const struct pinmux_ops pxa2xx_pinmux_ops = { 1778c2ecf20Sopenharmony_ci .get_functions_count = pxa2xx_get_functions_count, 1788c2ecf20Sopenharmony_ci .get_function_name = pxa2xx_pmx_get_func_name, 1798c2ecf20Sopenharmony_ci .get_function_groups = pxa2xx_pmx_get_func_groups, 1808c2ecf20Sopenharmony_ci .set_mux = pxa2xx_pmx_set_mux, 1818c2ecf20Sopenharmony_ci .gpio_set_direction = pxa2xx_pmx_gpio_set_direction, 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int pxa2xx_pconf_group_get(struct pinctrl_dev *pctldev, 1858c2ecf20Sopenharmony_ci unsigned group, 1868c2ecf20Sopenharmony_ci unsigned long *config) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 1898c2ecf20Sopenharmony_ci struct pxa_pinctrl_group *g = pctl->groups + group; 1908c2ecf20Sopenharmony_ci unsigned long flags; 1918c2ecf20Sopenharmony_ci unsigned pin = g->pin; 1928c2ecf20Sopenharmony_ci void __iomem *pgsr = pctl->base_pgsr[pin / 32]; 1938c2ecf20Sopenharmony_ci u32 val; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci spin_lock_irqsave(&pctl->lock, flags); 1968c2ecf20Sopenharmony_ci val = readl_relaxed(pgsr) & BIT(pin % 32); 1978c2ecf20Sopenharmony_ci *config = val ? PIN_CONFIG_LOW_POWER_MODE : 0; 1988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pctl->lock, flags); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci dev_dbg(pctl->dev, "get sleep gpio state(pin=%d) %d\n", 2018c2ecf20Sopenharmony_ci pin, !!val); 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int pxa2xx_pconf_group_set(struct pinctrl_dev *pctldev, 2068c2ecf20Sopenharmony_ci unsigned group, 2078c2ecf20Sopenharmony_ci unsigned long *configs, 2088c2ecf20Sopenharmony_ci unsigned num_configs) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); 2118c2ecf20Sopenharmony_ci struct pxa_pinctrl_group *g = pctl->groups + group; 2128c2ecf20Sopenharmony_ci unsigned long flags; 2138c2ecf20Sopenharmony_ci unsigned pin = g->pin; 2148c2ecf20Sopenharmony_ci void __iomem *pgsr = pctl->base_pgsr[pin / 32]; 2158c2ecf20Sopenharmony_ci int i, is_set = 0; 2168c2ecf20Sopenharmony_ci u32 val; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci for (i = 0; i < num_configs; i++) { 2198c2ecf20Sopenharmony_ci switch (pinconf_to_config_param(configs[i])) { 2208c2ecf20Sopenharmony_ci case PIN_CONFIG_LOW_POWER_MODE: 2218c2ecf20Sopenharmony_ci is_set = pinconf_to_config_argument(configs[i]); 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci default: 2248c2ecf20Sopenharmony_ci return -EINVAL; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci dev_dbg(pctl->dev, "set sleep gpio state(pin=%d) %d\n", 2298c2ecf20Sopenharmony_ci pin, is_set); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci spin_lock_irqsave(&pctl->lock, flags); 2328c2ecf20Sopenharmony_ci val = readl_relaxed(pgsr); 2338c2ecf20Sopenharmony_ci val = (val & ~BIT(pin % 32)) | (is_set ? BIT(pin % 32) : 0); 2348c2ecf20Sopenharmony_ci writel_relaxed(val, pgsr); 2358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pctl->lock, flags); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic const struct pinconf_ops pxa2xx_pconf_ops = { 2418c2ecf20Sopenharmony_ci .pin_config_group_get = pxa2xx_pconf_group_get, 2428c2ecf20Sopenharmony_ci .pin_config_group_set = pxa2xx_pconf_group_set, 2438c2ecf20Sopenharmony_ci .is_generic = true, 2448c2ecf20Sopenharmony_ci}; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic struct pinctrl_desc pxa2xx_pinctrl_desc = { 2478c2ecf20Sopenharmony_ci .confops = &pxa2xx_pconf_ops, 2488c2ecf20Sopenharmony_ci .pctlops = &pxa2xx_pctl_ops, 2498c2ecf20Sopenharmony_ci .pmxops = &pxa2xx_pinmux_ops, 2508c2ecf20Sopenharmony_ci}; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic const struct pxa_pinctrl_function * 2538c2ecf20Sopenharmony_cipxa2xx_find_function(struct pxa_pinctrl *pctl, const char *fname, 2548c2ecf20Sopenharmony_ci const struct pxa_pinctrl_function *functions) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci const struct pxa_pinctrl_function *func; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci for (func = functions; func->name; func++) 2598c2ecf20Sopenharmony_ci if (!strcmp(fname, func->name)) 2608c2ecf20Sopenharmony_ci return func; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return NULL; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int pxa2xx_build_functions(struct pxa_pinctrl *pctl) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci int i; 2688c2ecf20Sopenharmony_ci struct pxa_pinctrl_function *functions; 2698c2ecf20Sopenharmony_ci struct pxa_desc_function *df; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* 2728c2ecf20Sopenharmony_ci * Each pin can have at most 6 alternate functions, and 2 gpio functions 2738c2ecf20Sopenharmony_ci * which are common to each pin. As there are more than 2 pins without 2748c2ecf20Sopenharmony_ci * alternate function, 6 * npins is an absolute high limit of the number 2758c2ecf20Sopenharmony_ci * of functions. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci functions = devm_kcalloc(pctl->dev, pctl->npins * 6, 2788c2ecf20Sopenharmony_ci sizeof(*functions), GFP_KERNEL); 2798c2ecf20Sopenharmony_ci if (!functions) 2808c2ecf20Sopenharmony_ci return -ENOMEM; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci for (i = 0; i < pctl->npins; i++) 2838c2ecf20Sopenharmony_ci for (df = pctl->ppins[i].functions; df->name; df++) 2848c2ecf20Sopenharmony_ci if (!pxa2xx_find_function(pctl, df->name, functions)) 2858c2ecf20Sopenharmony_ci (functions + pctl->nfuncs++)->name = df->name; 2868c2ecf20Sopenharmony_ci pctl->functions = devm_kmemdup(pctl->dev, functions, 2878c2ecf20Sopenharmony_ci pctl->nfuncs * sizeof(*functions), 2888c2ecf20Sopenharmony_ci GFP_KERNEL); 2898c2ecf20Sopenharmony_ci if (!pctl->functions) 2908c2ecf20Sopenharmony_ci return -ENOMEM; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci devm_kfree(pctl->dev, functions); 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int pxa2xx_build_groups(struct pxa_pinctrl *pctl) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci int i, j, ngroups; 2998c2ecf20Sopenharmony_ci struct pxa_pinctrl_function *func; 3008c2ecf20Sopenharmony_ci struct pxa_desc_function *df; 3018c2ecf20Sopenharmony_ci char **gtmp; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci gtmp = devm_kmalloc_array(pctl->dev, pctl->npins, sizeof(*gtmp), 3048c2ecf20Sopenharmony_ci GFP_KERNEL); 3058c2ecf20Sopenharmony_ci if (!gtmp) 3068c2ecf20Sopenharmony_ci return -ENOMEM; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci for (i = 0; i < pctl->nfuncs; i++) { 3098c2ecf20Sopenharmony_ci ngroups = 0; 3108c2ecf20Sopenharmony_ci for (j = 0; j < pctl->npins; j++) 3118c2ecf20Sopenharmony_ci for (df = pctl->ppins[j].functions; df->name; 3128c2ecf20Sopenharmony_ci df++) 3138c2ecf20Sopenharmony_ci if (!strcmp(pctl->functions[i].name, 3148c2ecf20Sopenharmony_ci df->name)) 3158c2ecf20Sopenharmony_ci gtmp[ngroups++] = (char *) 3168c2ecf20Sopenharmony_ci pctl->ppins[j].pin.name; 3178c2ecf20Sopenharmony_ci func = pctl->functions + i; 3188c2ecf20Sopenharmony_ci func->ngroups = ngroups; 3198c2ecf20Sopenharmony_ci func->groups = 3208c2ecf20Sopenharmony_ci devm_kmalloc_array(pctl->dev, ngroups, 3218c2ecf20Sopenharmony_ci sizeof(char *), GFP_KERNEL); 3228c2ecf20Sopenharmony_ci if (!func->groups) 3238c2ecf20Sopenharmony_ci return -ENOMEM; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci memcpy(func->groups, gtmp, ngroups * sizeof(*gtmp)); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci devm_kfree(pctl->dev, gtmp); 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int pxa2xx_build_state(struct pxa_pinctrl *pctl, 3338c2ecf20Sopenharmony_ci const struct pxa_desc_pin *ppins, int npins) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct pxa_pinctrl_group *group; 3368c2ecf20Sopenharmony_ci struct pinctrl_pin_desc *pins; 3378c2ecf20Sopenharmony_ci int ret, i; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci pctl->npins = npins; 3408c2ecf20Sopenharmony_ci pctl->ppins = ppins; 3418c2ecf20Sopenharmony_ci pctl->ngroups = npins; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci pctl->desc.npins = npins; 3448c2ecf20Sopenharmony_ci pins = devm_kcalloc(pctl->dev, npins, sizeof(*pins), GFP_KERNEL); 3458c2ecf20Sopenharmony_ci if (!pins) 3468c2ecf20Sopenharmony_ci return -ENOMEM; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci pctl->desc.pins = pins; 3498c2ecf20Sopenharmony_ci for (i = 0; i < npins; i++) 3508c2ecf20Sopenharmony_ci pins[i] = ppins[i].pin; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci pctl->groups = devm_kmalloc_array(pctl->dev, pctl->ngroups, 3538c2ecf20Sopenharmony_ci sizeof(*pctl->groups), GFP_KERNEL); 3548c2ecf20Sopenharmony_ci if (!pctl->groups) 3558c2ecf20Sopenharmony_ci return -ENOMEM; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci for (i = 0; i < npins; i++) { 3588c2ecf20Sopenharmony_ci group = pctl->groups + i; 3598c2ecf20Sopenharmony_ci group->name = ppins[i].pin.name; 3608c2ecf20Sopenharmony_ci group->pin = ppins[i].pin.number; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci ret = pxa2xx_build_functions(pctl); 3648c2ecf20Sopenharmony_ci if (ret) 3658c2ecf20Sopenharmony_ci return ret; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci ret = pxa2xx_build_groups(pctl); 3688c2ecf20Sopenharmony_ci if (ret) 3698c2ecf20Sopenharmony_ci return ret; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ciint pxa2xx_pinctrl_init(struct platform_device *pdev, 3758c2ecf20Sopenharmony_ci const struct pxa_desc_pin *ppins, int npins, 3768c2ecf20Sopenharmony_ci void __iomem *base_gafr[], void __iomem *base_gpdr[], 3778c2ecf20Sopenharmony_ci void __iomem *base_pgsr[]) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct pxa_pinctrl *pctl; 3808c2ecf20Sopenharmony_ci int ret, i, maxpin = 0; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci for (i = 0; i < npins; i++) 3838c2ecf20Sopenharmony_ci maxpin = max_t(int, ppins[i].pin.number, maxpin); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); 3868c2ecf20Sopenharmony_ci if (!pctl) 3878c2ecf20Sopenharmony_ci return -ENOMEM; 3888c2ecf20Sopenharmony_ci pctl->base_gafr = devm_kcalloc(&pdev->dev, roundup(maxpin, 16), 3898c2ecf20Sopenharmony_ci sizeof(*pctl->base_gafr), GFP_KERNEL); 3908c2ecf20Sopenharmony_ci pctl->base_gpdr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32), 3918c2ecf20Sopenharmony_ci sizeof(*pctl->base_gpdr), GFP_KERNEL); 3928c2ecf20Sopenharmony_ci pctl->base_pgsr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32), 3938c2ecf20Sopenharmony_ci sizeof(*pctl->base_pgsr), GFP_KERNEL); 3948c2ecf20Sopenharmony_ci if (!pctl->base_gafr || !pctl->base_gpdr || !pctl->base_pgsr) 3958c2ecf20Sopenharmony_ci return -ENOMEM; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pctl); 3988c2ecf20Sopenharmony_ci spin_lock_init(&pctl->lock); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci pctl->dev = &pdev->dev; 4018c2ecf20Sopenharmony_ci pctl->desc = pxa2xx_pinctrl_desc; 4028c2ecf20Sopenharmony_ci pctl->desc.name = dev_name(&pdev->dev); 4038c2ecf20Sopenharmony_ci pctl->desc.owner = THIS_MODULE; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci for (i = 0; i < roundup(maxpin, 16); i += 16) 4068c2ecf20Sopenharmony_ci pctl->base_gafr[i / 16] = base_gafr[i / 16]; 4078c2ecf20Sopenharmony_ci for (i = 0; i < roundup(maxpin, 32); i += 32) { 4088c2ecf20Sopenharmony_ci pctl->base_gpdr[i / 32] = base_gpdr[i / 32]; 4098c2ecf20Sopenharmony_ci pctl->base_pgsr[i / 32] = base_pgsr[i / 32]; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci ret = pxa2xx_build_state(pctl, ppins, npins); 4138c2ecf20Sopenharmony_ci if (ret) 4148c2ecf20Sopenharmony_ci return ret; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->desc, pctl); 4178c2ecf20Sopenharmony_ci if (IS_ERR(pctl->pctl_dev)) { 4188c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); 4198c2ecf20Sopenharmony_ci return PTR_ERR(pctl->pctl_dev); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "initialized pxa2xx pinctrl driver\n"); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pxa2xx_pinctrl_init); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>"); 4298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Marvell PXA2xx pinctrl driver"); 4308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 431