18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Driver for the ST Microelectronics SPEAr pinmux 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2012 ST Microelectronics 58c2ecf20Sopenharmony_ci * Viresh Kumar <vireshk@kernel.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Inspired from: 88c2ecf20Sopenharmony_ci * - U300 Pinctl drivers 98c2ecf20Sopenharmony_ci * - Tegra Pinctl drivers 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 128c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 138c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/of.h> 198c2ecf20Sopenharmony_ci#include <linux/of_address.h> 208c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 218c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h> 228c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 238c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 248c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "pinctrl-spear.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define DRIVER_NAME "spear-pinmux" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic void muxregs_endisable(struct spear_pmx *pmx, 328c2ecf20Sopenharmony_ci struct spear_muxreg *muxregs, u8 count, bool enable) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct spear_muxreg *muxreg; 358c2ecf20Sopenharmony_ci u32 val, temp, j; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci for (j = 0; j < count; j++) { 388c2ecf20Sopenharmony_ci muxreg = &muxregs[j]; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci val = pmx_readl(pmx, muxreg->reg); 418c2ecf20Sopenharmony_ci val &= ~muxreg->mask; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (enable) 448c2ecf20Sopenharmony_ci temp = muxreg->val; 458c2ecf20Sopenharmony_ci else 468c2ecf20Sopenharmony_ci temp = ~muxreg->val; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci val |= muxreg->mask & temp; 498c2ecf20Sopenharmony_ci pmx_writel(pmx, val, muxreg->reg); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int set_mode(struct spear_pmx *pmx, int mode) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct spear_pmx_mode *pmx_mode = NULL; 568c2ecf20Sopenharmony_ci int i; 578c2ecf20Sopenharmony_ci u32 val; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (!pmx->machdata->pmx_modes || !pmx->machdata->npmx_modes) 608c2ecf20Sopenharmony_ci return -EINVAL; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci for (i = 0; i < pmx->machdata->npmx_modes; i++) { 638c2ecf20Sopenharmony_ci if (pmx->machdata->pmx_modes[i]->mode == (1 << mode)) { 648c2ecf20Sopenharmony_ci pmx_mode = pmx->machdata->pmx_modes[i]; 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!pmx_mode) 708c2ecf20Sopenharmony_ci return -EINVAL; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci val = pmx_readl(pmx, pmx_mode->reg); 738c2ecf20Sopenharmony_ci val &= ~pmx_mode->mask; 748c2ecf20Sopenharmony_ci val |= pmx_mode->val; 758c2ecf20Sopenharmony_ci pmx_writel(pmx, val, pmx_mode->reg); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci pmx->machdata->mode = pmx_mode->mode; 788c2ecf20Sopenharmony_ci dev_info(pmx->dev, "Configured Mode: %s with id: %x\n\n", 798c2ecf20Sopenharmony_ci pmx_mode->name ? pmx_mode->name : "no_name", 808c2ecf20Sopenharmony_ci pmx_mode->reg); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_civoid pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup, 868c2ecf20Sopenharmony_ci unsigned count, u16 reg) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci int i, j; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) 918c2ecf20Sopenharmony_ci for (j = 0; j < gpio_pingroup[i].nmuxregs; j++) 928c2ecf20Sopenharmony_ci gpio_pingroup[i].muxregs[j].reg = reg; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_civoid pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct spear_pingroup *pgroup; 988c2ecf20Sopenharmony_ci struct spear_modemux *modemux; 998c2ecf20Sopenharmony_ci int i, j, group; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci for (group = 0; group < machdata->ngroups; group++) { 1028c2ecf20Sopenharmony_ci pgroup = machdata->groups[group]; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci for (i = 0; i < pgroup->nmodemuxs; i++) { 1058c2ecf20Sopenharmony_ci modemux = &pgroup->modemuxs[i]; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci for (j = 0; j < modemux->nmuxregs; j++) 1088c2ecf20Sopenharmony_ci if (modemux->muxregs[j].reg == 0xFFFF) 1098c2ecf20Sopenharmony_ci modemux->muxregs[j].reg = reg; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int spear_pinctrl_get_groups_cnt(struct pinctrl_dev *pctldev) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return pmx->machdata->ngroups; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic const char *spear_pinctrl_get_group_name(struct pinctrl_dev *pctldev, 1228c2ecf20Sopenharmony_ci unsigned group) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return pmx->machdata->groups[group]->name; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int spear_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, 1308c2ecf20Sopenharmony_ci unsigned group, const unsigned **pins, unsigned *num_pins) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci *pins = pmx->machdata->groups[group]->pins; 1358c2ecf20Sopenharmony_ci *num_pins = pmx->machdata->groups[group]->npins; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, 1418c2ecf20Sopenharmony_ci struct seq_file *s, unsigned offset) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci seq_printf(s, " " DRIVER_NAME); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, 1478c2ecf20Sopenharmony_ci struct device_node *np_config, 1488c2ecf20Sopenharmony_ci struct pinctrl_map **map, 1498c2ecf20Sopenharmony_ci unsigned *num_maps) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 1528c2ecf20Sopenharmony_ci struct device_node *np; 1538c2ecf20Sopenharmony_ci struct property *prop; 1548c2ecf20Sopenharmony_ci const char *function, *group; 1558c2ecf20Sopenharmony_ci int ret, index = 0, count = 0; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* calculate number of maps required */ 1588c2ecf20Sopenharmony_ci for_each_child_of_node(np_config, np) { 1598c2ecf20Sopenharmony_ci ret = of_property_read_string(np, "st,function", &function); 1608c2ecf20Sopenharmony_ci if (ret < 0) { 1618c2ecf20Sopenharmony_ci of_node_put(np); 1628c2ecf20Sopenharmony_ci return ret; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci ret = of_property_count_strings(np, "st,pins"); 1668c2ecf20Sopenharmony_ci if (ret < 0) { 1678c2ecf20Sopenharmony_ci of_node_put(np); 1688c2ecf20Sopenharmony_ci return ret; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci count += ret; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (!count) { 1758c2ecf20Sopenharmony_ci dev_err(pmx->dev, "No child nodes passed via DT\n"); 1768c2ecf20Sopenharmony_ci return -ENODEV; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci *map = kcalloc(count, sizeof(**map), GFP_KERNEL); 1808c2ecf20Sopenharmony_ci if (!*map) 1818c2ecf20Sopenharmony_ci return -ENOMEM; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci for_each_child_of_node(np_config, np) { 1848c2ecf20Sopenharmony_ci of_property_read_string(np, "st,function", &function); 1858c2ecf20Sopenharmony_ci of_property_for_each_string(np, "st,pins", prop, group) { 1868c2ecf20Sopenharmony_ci (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP; 1878c2ecf20Sopenharmony_ci (*map)[index].data.mux.group = group; 1888c2ecf20Sopenharmony_ci (*map)[index].data.mux.function = function; 1898c2ecf20Sopenharmony_ci index++; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci *num_maps = count; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, 1998c2ecf20Sopenharmony_ci struct pinctrl_map *map, 2008c2ecf20Sopenharmony_ci unsigned num_maps) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci kfree(map); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic const struct pinctrl_ops spear_pinctrl_ops = { 2068c2ecf20Sopenharmony_ci .get_groups_count = spear_pinctrl_get_groups_cnt, 2078c2ecf20Sopenharmony_ci .get_group_name = spear_pinctrl_get_group_name, 2088c2ecf20Sopenharmony_ci .get_group_pins = spear_pinctrl_get_group_pins, 2098c2ecf20Sopenharmony_ci .pin_dbg_show = spear_pinctrl_pin_dbg_show, 2108c2ecf20Sopenharmony_ci .dt_node_to_map = spear_pinctrl_dt_node_to_map, 2118c2ecf20Sopenharmony_ci .dt_free_map = spear_pinctrl_dt_free_map, 2128c2ecf20Sopenharmony_ci}; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int spear_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return pmx->machdata->nfunctions; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic const char *spear_pinctrl_get_func_name(struct pinctrl_dev *pctldev, 2228c2ecf20Sopenharmony_ci unsigned function) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return pmx->machdata->functions[function]->name; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int spear_pinctrl_get_func_groups(struct pinctrl_dev *pctldev, 2308c2ecf20Sopenharmony_ci unsigned function, const char *const **groups, 2318c2ecf20Sopenharmony_ci unsigned * const ngroups) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci *groups = pmx->machdata->functions[function]->groups; 2368c2ecf20Sopenharmony_ci *ngroups = pmx->machdata->functions[function]->ngroups; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, 2428c2ecf20Sopenharmony_ci unsigned function, unsigned group, bool enable) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 2458c2ecf20Sopenharmony_ci const struct spear_pingroup *pgroup; 2468c2ecf20Sopenharmony_ci const struct spear_modemux *modemux; 2478c2ecf20Sopenharmony_ci int i; 2488c2ecf20Sopenharmony_ci bool found = false; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci pgroup = pmx->machdata->groups[group]; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci for (i = 0; i < pgroup->nmodemuxs; i++) { 2538c2ecf20Sopenharmony_ci modemux = &pgroup->modemuxs[i]; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* SoC have any modes */ 2568c2ecf20Sopenharmony_ci if (pmx->machdata->modes_supported) { 2578c2ecf20Sopenharmony_ci if (!(pmx->machdata->mode & modemux->modes)) 2588c2ecf20Sopenharmony_ci continue; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci found = true; 2628c2ecf20Sopenharmony_ci muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs, 2638c2ecf20Sopenharmony_ci enable); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (!found) { 2678c2ecf20Sopenharmony_ci dev_err(pmx->dev, "pinmux group: %s not supported\n", 2688c2ecf20Sopenharmony_ci pgroup->name); 2698c2ecf20Sopenharmony_ci return -ENODEV; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return 0; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic int spear_pinctrl_set_mux(struct pinctrl_dev *pctldev, unsigned function, 2768c2ecf20Sopenharmony_ci unsigned group) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci return spear_pinctrl_endisable(pctldev, function, group, true); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci/* gpio with pinmux */ 2828c2ecf20Sopenharmony_cistatic struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx, 2838c2ecf20Sopenharmony_ci unsigned pin) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct spear_gpio_pingroup *gpio_pingroup; 2868c2ecf20Sopenharmony_ci int i, j; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (!pmx->machdata->gpio_pingroups) 2898c2ecf20Sopenharmony_ci return NULL; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci for (i = 0; i < pmx->machdata->ngpio_pingroups; i++) { 2928c2ecf20Sopenharmony_ci gpio_pingroup = &pmx->machdata->gpio_pingroups[i]; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci for (j = 0; j < gpio_pingroup->npins; j++) { 2958c2ecf20Sopenharmony_ci if (gpio_pingroup->pins[j] == pin) 2968c2ecf20Sopenharmony_ci return gpio_pingroup; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci return NULL; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int gpio_request_endisable(struct pinctrl_dev *pctldev, 3048c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, unsigned offset, bool enable) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); 3078c2ecf20Sopenharmony_ci struct spear_pinctrl_machdata *machdata = pmx->machdata; 3088c2ecf20Sopenharmony_ci struct spear_gpio_pingroup *gpio_pingroup; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * Some SoC have configuration options applicable to group of pins, 3128c2ecf20Sopenharmony_ci * rather than a single pin. 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ci gpio_pingroup = get_gpio_pingroup(pmx, offset); 3158c2ecf20Sopenharmony_ci if (gpio_pingroup) 3168c2ecf20Sopenharmony_ci muxregs_endisable(pmx, gpio_pingroup->muxregs, 3178c2ecf20Sopenharmony_ci gpio_pingroup->nmuxregs, enable); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* 3208c2ecf20Sopenharmony_ci * SoC may need some extra configurations, or configurations for single 3218c2ecf20Sopenharmony_ci * pin 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci if (machdata->gpio_request_endisable) 3248c2ecf20Sopenharmony_ci machdata->gpio_request_endisable(pmx, offset, enable); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int gpio_request_enable(struct pinctrl_dev *pctldev, 3308c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, unsigned offset) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci return gpio_request_endisable(pctldev, range, offset, true); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic void gpio_disable_free(struct pinctrl_dev *pctldev, 3368c2ecf20Sopenharmony_ci struct pinctrl_gpio_range *range, unsigned offset) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci gpio_request_endisable(pctldev, range, offset, false); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic const struct pinmux_ops spear_pinmux_ops = { 3428c2ecf20Sopenharmony_ci .get_functions_count = spear_pinctrl_get_funcs_count, 3438c2ecf20Sopenharmony_ci .get_function_name = spear_pinctrl_get_func_name, 3448c2ecf20Sopenharmony_ci .get_function_groups = spear_pinctrl_get_func_groups, 3458c2ecf20Sopenharmony_ci .set_mux = spear_pinctrl_set_mux, 3468c2ecf20Sopenharmony_ci .gpio_request_enable = gpio_request_enable, 3478c2ecf20Sopenharmony_ci .gpio_disable_free = gpio_disable_free, 3488c2ecf20Sopenharmony_ci}; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic struct pinctrl_desc spear_pinctrl_desc = { 3518c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 3528c2ecf20Sopenharmony_ci .pctlops = &spear_pinctrl_ops, 3538c2ecf20Sopenharmony_ci .pmxops = &spear_pinmux_ops, 3548c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ciint spear_pinctrl_probe(struct platform_device *pdev, 3588c2ecf20Sopenharmony_ci struct spear_pinctrl_machdata *machdata) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 3618c2ecf20Sopenharmony_ci struct spear_pmx *pmx; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (!machdata) 3648c2ecf20Sopenharmony_ci return -ENODEV; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); 3678c2ecf20Sopenharmony_ci if (!pmx) 3688c2ecf20Sopenharmony_ci return -ENOMEM; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci pmx->vbase = devm_platform_ioremap_resource(pdev, 0); 3718c2ecf20Sopenharmony_ci if (IS_ERR(pmx->vbase)) 3728c2ecf20Sopenharmony_ci return PTR_ERR(pmx->vbase); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci pmx->dev = &pdev->dev; 3758c2ecf20Sopenharmony_ci pmx->machdata = machdata; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* configure mode, if supported by SoC */ 3788c2ecf20Sopenharmony_ci if (machdata->modes_supported) { 3798c2ecf20Sopenharmony_ci int mode = 0; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (of_property_read_u32(np, "st,pinmux-mode", &mode)) { 3828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "OF: pinmux mode not passed\n"); 3838c2ecf20Sopenharmony_ci return -EINVAL; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (set_mode(pmx, mode)) { 3878c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "OF: Couldn't configure mode: %x\n", 3888c2ecf20Sopenharmony_ci mode); 3898c2ecf20Sopenharmony_ci return -EINVAL; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pmx); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci spear_pinctrl_desc.pins = machdata->pins; 3968c2ecf20Sopenharmony_ci spear_pinctrl_desc.npins = machdata->npins; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci pmx->pctl = devm_pinctrl_register(&pdev->dev, &spear_pinctrl_desc, pmx); 3998c2ecf20Sopenharmony_ci if (IS_ERR(pmx->pctl)) { 4008c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); 4018c2ecf20Sopenharmony_ci return PTR_ERR(pmx->pctl); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci} 406