18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Core driver for the imx pin controller in imx1/21/27 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2013 Pengutronix 68c2ecf20Sopenharmony_ci// Author: Markus Pargmann <mpa@pengutronix.de> 78c2ecf20Sopenharmony_ci// 88c2ecf20Sopenharmony_ci// Based on pinctrl-imx.c: 98c2ecf20Sopenharmony_ci// Author: Dong Aisheng <dong.aisheng@linaro.org> 108c2ecf20Sopenharmony_ci// Copyright (C) 2012 Freescale Semiconductor, Inc. 118c2ecf20Sopenharmony_ci// Copyright (C) 2012 Linaro Ltd. 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/bitops.h> 148c2ecf20Sopenharmony_ci#include <linux/err.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h> 208c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 218c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 228c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "../core.h" 268c2ecf20Sopenharmony_ci#include "pinctrl-imx1.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct imx1_pinctrl { 298c2ecf20Sopenharmony_ci struct device *dev; 308c2ecf20Sopenharmony_ci struct pinctrl_dev *pctl; 318c2ecf20Sopenharmony_ci void __iomem *base; 328c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info; 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * MX1 register offsets 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define MX1_DDIR 0x00 408c2ecf20Sopenharmony_ci#define MX1_OCR 0x04 418c2ecf20Sopenharmony_ci#define MX1_ICONFA 0x0c 428c2ecf20Sopenharmony_ci#define MX1_ICONFB 0x14 438c2ecf20Sopenharmony_ci#define MX1_GIUS 0x20 448c2ecf20Sopenharmony_ci#define MX1_GPR 0x38 458c2ecf20Sopenharmony_ci#define MX1_PUEN 0x40 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define MX1_PORT_STRIDE 0x100 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * MUX_ID format defines 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci#define MX1_MUX_FUNCTION(val) (BIT(0) & val) 548c2ecf20Sopenharmony_ci#define MX1_MUX_GPIO(val) ((BIT(1) & val) >> 1) 558c2ecf20Sopenharmony_ci#define MX1_MUX_DIR(val) ((BIT(2) & val) >> 2) 568c2ecf20Sopenharmony_ci#define MX1_MUX_OCONF(val) (((BIT(4) | BIT(5)) & val) >> 4) 578c2ecf20Sopenharmony_ci#define MX1_MUX_ICONFA(val) (((BIT(8) | BIT(9)) & val) >> 8) 588c2ecf20Sopenharmony_ci#define MX1_MUX_ICONFB(val) (((BIT(10) | BIT(11)) & val) >> 10) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * IMX1 IOMUXC manages the pins based on ports. Each port has 32 pins. IOMUX 638c2ecf20Sopenharmony_ci * control registers are separated into function, output configuration, input 648c2ecf20Sopenharmony_ci * configuration A, input configuration B, GPIO in use and data direction. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * Those controls that are represented by 1 bit have a direct mapping between 678c2ecf20Sopenharmony_ci * bit position and pin id. If they are represented by 2 bit, the lower 16 pins 688c2ecf20Sopenharmony_ci * are in the first register and the upper 16 pins in the second (next) 698c2ecf20Sopenharmony_ci * register. pin_id is stored in bit (pin_id%16)*2 and the bit above. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * Calculates the register offset from a pin_id 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistatic void __iomem *imx1_mem(struct imx1_pinctrl *ipctl, unsigned int pin_id) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci unsigned int port = pin_id / 32; 788c2ecf20Sopenharmony_ci return ipctl->base + port * MX1_PORT_STRIDE; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* 828c2ecf20Sopenharmony_ci * Write to a register with 2 bits per pin. The function will automatically 838c2ecf20Sopenharmony_ci * use the next register if the pin is managed in the second register. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_cistatic void imx1_write_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, 868c2ecf20Sopenharmony_ci u32 value, u32 reg_offset) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; 898c2ecf20Sopenharmony_ci int offset = (pin_id % 16) * 2; /* offset, regardless of register used */ 908c2ecf20Sopenharmony_ci int mask = ~(0x3 << offset); /* Mask for 2 bits at offset */ 918c2ecf20Sopenharmony_ci u32 old_val; 928c2ecf20Sopenharmony_ci u32 new_val; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* Use the next register if the pin's port pin number is >=16 */ 958c2ecf20Sopenharmony_ci if (pin_id % 32 >= 16) 968c2ecf20Sopenharmony_ci reg += 0x04; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci dev_dbg(ipctl->dev, "write: register 0x%p offset %d value 0x%x\n", 998c2ecf20Sopenharmony_ci reg, offset, value); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Get current state of pins */ 1028c2ecf20Sopenharmony_ci old_val = readl(reg); 1038c2ecf20Sopenharmony_ci old_val &= mask; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci new_val = value & 0x3; /* Make sure value is really 2 bit */ 1068c2ecf20Sopenharmony_ci new_val <<= offset; 1078c2ecf20Sopenharmony_ci new_val |= old_val;/* Set new state for pin_id */ 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci writel(new_val, reg); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void imx1_write_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, 1138c2ecf20Sopenharmony_ci u32 value, u32 reg_offset) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; 1168c2ecf20Sopenharmony_ci int offset = pin_id % 32; 1178c2ecf20Sopenharmony_ci int mask = ~BIT_MASK(offset); 1188c2ecf20Sopenharmony_ci u32 old_val; 1198c2ecf20Sopenharmony_ci u32 new_val; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Get current state of pins */ 1228c2ecf20Sopenharmony_ci old_val = readl(reg); 1238c2ecf20Sopenharmony_ci old_val &= mask; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci new_val = value & 0x1; /* Make sure value is really 1 bit */ 1268c2ecf20Sopenharmony_ci new_val <<= offset; 1278c2ecf20Sopenharmony_ci new_val |= old_val;/* Set new state for pin_id */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci writel(new_val, reg); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int imx1_read_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, 1338c2ecf20Sopenharmony_ci u32 reg_offset) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; 1368c2ecf20Sopenharmony_ci int offset = (pin_id % 16) * 2; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* Use the next register if the pin's port pin number is >=16 */ 1398c2ecf20Sopenharmony_ci if (pin_id % 32 >= 16) 1408c2ecf20Sopenharmony_ci reg += 0x04; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return (readl(reg) & (BIT(offset) | BIT(offset+1))) >> offset; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int imx1_read_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, 1468c2ecf20Sopenharmony_ci u32 reg_offset) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; 1498c2ecf20Sopenharmony_ci int offset = pin_id % 32; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return !!(readl(reg) & BIT(offset)); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic inline const struct imx1_pin_group *imx1_pinctrl_find_group_by_name( 1558c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info, 1568c2ecf20Sopenharmony_ci const char *name) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci const struct imx1_pin_group *grp = NULL; 1598c2ecf20Sopenharmony_ci int i; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci for (i = 0; i < info->ngroups; i++) { 1628c2ecf20Sopenharmony_ci if (!strcmp(info->groups[i].name, name)) { 1638c2ecf20Sopenharmony_ci grp = &info->groups[i]; 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return grp; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int imx1_get_groups_count(struct pinctrl_dev *pctldev) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 1748c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return info->ngroups; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic const char *imx1_get_group_name(struct pinctrl_dev *pctldev, 1808c2ecf20Sopenharmony_ci unsigned selector) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 1838c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return info->groups[selector].name; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int imx1_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, 1898c2ecf20Sopenharmony_ci const unsigned int **pins, 1908c2ecf20Sopenharmony_ci unsigned *npins) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 1938c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (selector >= info->ngroups) 1968c2ecf20Sopenharmony_ci return -EINVAL; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci *pins = info->groups[selector].pin_ids; 1998c2ecf20Sopenharmony_ci *npins = info->groups[selector].npins; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void imx1_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 2058c2ecf20Sopenharmony_ci unsigned offset) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci seq_printf(s, "GPIO %d, function %d, direction %d, oconf %d, iconfa %d, iconfb %d", 2108c2ecf20Sopenharmony_ci imx1_read_bit(ipctl, offset, MX1_GIUS), 2118c2ecf20Sopenharmony_ci imx1_read_bit(ipctl, offset, MX1_GPR), 2128c2ecf20Sopenharmony_ci imx1_read_bit(ipctl, offset, MX1_DDIR), 2138c2ecf20Sopenharmony_ci imx1_read_2bit(ipctl, offset, MX1_OCR), 2148c2ecf20Sopenharmony_ci imx1_read_2bit(ipctl, offset, MX1_ICONFA), 2158c2ecf20Sopenharmony_ci imx1_read_2bit(ipctl, offset, MX1_ICONFB)); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int imx1_dt_node_to_map(struct pinctrl_dev *pctldev, 2198c2ecf20Sopenharmony_ci struct device_node *np, 2208c2ecf20Sopenharmony_ci struct pinctrl_map **map, unsigned *num_maps) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 2238c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 2248c2ecf20Sopenharmony_ci const struct imx1_pin_group *grp; 2258c2ecf20Sopenharmony_ci struct pinctrl_map *new_map; 2268c2ecf20Sopenharmony_ci struct device_node *parent; 2278c2ecf20Sopenharmony_ci int map_num = 1; 2288c2ecf20Sopenharmony_ci int i, j; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * first find the group of this node and check if we need create 2328c2ecf20Sopenharmony_ci * config maps for pins 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci grp = imx1_pinctrl_find_group_by_name(info, np->name); 2358c2ecf20Sopenharmony_ci if (!grp) { 2368c2ecf20Sopenharmony_ci dev_err(info->dev, "unable to find group for node %pOFn\n", 2378c2ecf20Sopenharmony_ci np); 2388c2ecf20Sopenharmony_ci return -EINVAL; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci for (i = 0; i < grp->npins; i++) 2428c2ecf20Sopenharmony_ci map_num++; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map), 2458c2ecf20Sopenharmony_ci GFP_KERNEL); 2468c2ecf20Sopenharmony_ci if (!new_map) 2478c2ecf20Sopenharmony_ci return -ENOMEM; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci *map = new_map; 2508c2ecf20Sopenharmony_ci *num_maps = map_num; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* create mux map */ 2538c2ecf20Sopenharmony_ci parent = of_get_parent(np); 2548c2ecf20Sopenharmony_ci if (!parent) { 2558c2ecf20Sopenharmony_ci kfree(new_map); 2568c2ecf20Sopenharmony_ci return -EINVAL; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; 2598c2ecf20Sopenharmony_ci new_map[0].data.mux.function = parent->name; 2608c2ecf20Sopenharmony_ci new_map[0].data.mux.group = np->name; 2618c2ecf20Sopenharmony_ci of_node_put(parent); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* create config map */ 2648c2ecf20Sopenharmony_ci new_map++; 2658c2ecf20Sopenharmony_ci for (i = j = 0; i < grp->npins; i++) { 2668c2ecf20Sopenharmony_ci new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; 2678c2ecf20Sopenharmony_ci new_map[j].data.configs.group_or_pin = 2688c2ecf20Sopenharmony_ci pin_get_name(pctldev, grp->pins[i].pin_id); 2698c2ecf20Sopenharmony_ci new_map[j].data.configs.configs = &grp->pins[i].config; 2708c2ecf20Sopenharmony_ci new_map[j].data.configs.num_configs = 1; 2718c2ecf20Sopenharmony_ci j++; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", 2758c2ecf20Sopenharmony_ci (*map)->data.mux.function, (*map)->data.mux.group, map_num); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic void imx1_dt_free_map(struct pinctrl_dev *pctldev, 2818c2ecf20Sopenharmony_ci struct pinctrl_map *map, unsigned num_maps) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci kfree(map); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic const struct pinctrl_ops imx1_pctrl_ops = { 2878c2ecf20Sopenharmony_ci .get_groups_count = imx1_get_groups_count, 2888c2ecf20Sopenharmony_ci .get_group_name = imx1_get_group_name, 2898c2ecf20Sopenharmony_ci .get_group_pins = imx1_get_group_pins, 2908c2ecf20Sopenharmony_ci .pin_dbg_show = imx1_pin_dbg_show, 2918c2ecf20Sopenharmony_ci .dt_node_to_map = imx1_dt_node_to_map, 2928c2ecf20Sopenharmony_ci .dt_free_map = imx1_dt_free_map, 2938c2ecf20Sopenharmony_ci}; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int imx1_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, 2968c2ecf20Sopenharmony_ci unsigned group) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 2998c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 3008c2ecf20Sopenharmony_ci const struct imx1_pin *pins; 3018c2ecf20Sopenharmony_ci unsigned int npins; 3028c2ecf20Sopenharmony_ci int i; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* 3058c2ecf20Sopenharmony_ci * Configure the mux mode for each pin in the group for a specific 3068c2ecf20Sopenharmony_ci * function. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ci pins = info->groups[group].pins; 3098c2ecf20Sopenharmony_ci npins = info->groups[group].npins; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci WARN_ON(!pins || !npins); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci dev_dbg(ipctl->dev, "enable function %s group %s\n", 3148c2ecf20Sopenharmony_ci info->functions[selector].name, info->groups[group].name); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci for (i = 0; i < npins; i++) { 3178c2ecf20Sopenharmony_ci unsigned int mux = pins[i].mux_id; 3188c2ecf20Sopenharmony_ci unsigned int pin_id = pins[i].pin_id; 3198c2ecf20Sopenharmony_ci unsigned int afunction = MX1_MUX_FUNCTION(mux); 3208c2ecf20Sopenharmony_ci unsigned int gpio_in_use = MX1_MUX_GPIO(mux); 3218c2ecf20Sopenharmony_ci unsigned int direction = MX1_MUX_DIR(mux); 3228c2ecf20Sopenharmony_ci unsigned int gpio_oconf = MX1_MUX_OCONF(mux); 3238c2ecf20Sopenharmony_ci unsigned int gpio_iconfa = MX1_MUX_ICONFA(mux); 3248c2ecf20Sopenharmony_ci unsigned int gpio_iconfb = MX1_MUX_ICONFB(mux); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci dev_dbg(pctldev->dev, "%s, pin 0x%x, function %d, gpio %d, direction %d, oconf %d, iconfa %d, iconfb %d\n", 3278c2ecf20Sopenharmony_ci __func__, pin_id, afunction, gpio_in_use, 3288c2ecf20Sopenharmony_ci direction, gpio_oconf, gpio_iconfa, 3298c2ecf20Sopenharmony_ci gpio_iconfb); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci imx1_write_bit(ipctl, pin_id, gpio_in_use, MX1_GIUS); 3328c2ecf20Sopenharmony_ci imx1_write_bit(ipctl, pin_id, direction, MX1_DDIR); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (gpio_in_use) { 3358c2ecf20Sopenharmony_ci imx1_write_2bit(ipctl, pin_id, gpio_oconf, MX1_OCR); 3368c2ecf20Sopenharmony_ci imx1_write_2bit(ipctl, pin_id, gpio_iconfa, 3378c2ecf20Sopenharmony_ci MX1_ICONFA); 3388c2ecf20Sopenharmony_ci imx1_write_2bit(ipctl, pin_id, gpio_iconfb, 3398c2ecf20Sopenharmony_ci MX1_ICONFB); 3408c2ecf20Sopenharmony_ci } else { 3418c2ecf20Sopenharmony_ci imx1_write_bit(ipctl, pin_id, afunction, MX1_GPR); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int imx1_pmx_get_funcs_count(struct pinctrl_dev *pctldev) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 3518c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return info->nfunctions; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic const char *imx1_pmx_get_func_name(struct pinctrl_dev *pctldev, 3578c2ecf20Sopenharmony_ci unsigned selector) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 3608c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return info->functions[selector].name; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int imx1_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, 3668c2ecf20Sopenharmony_ci const char * const **groups, 3678c2ecf20Sopenharmony_ci unsigned * const num_groups) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 3708c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci *groups = info->functions[selector].groups; 3738c2ecf20Sopenharmony_ci *num_groups = info->functions[selector].num_groups; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic const struct pinmux_ops imx1_pmx_ops = { 3798c2ecf20Sopenharmony_ci .get_functions_count = imx1_pmx_get_funcs_count, 3808c2ecf20Sopenharmony_ci .get_function_name = imx1_pmx_get_func_name, 3818c2ecf20Sopenharmony_ci .get_function_groups = imx1_pmx_get_groups, 3828c2ecf20Sopenharmony_ci .set_mux = imx1_pmx_set, 3838c2ecf20Sopenharmony_ci}; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int imx1_pinconf_get(struct pinctrl_dev *pctldev, 3868c2ecf20Sopenharmony_ci unsigned pin_id, unsigned long *config) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci *config = imx1_read_bit(ipctl, pin_id, MX1_PUEN); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return 0; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int imx1_pinconf_set(struct pinctrl_dev *pctldev, 3968c2ecf20Sopenharmony_ci unsigned pin_id, unsigned long *configs, 3978c2ecf20Sopenharmony_ci unsigned num_configs) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 4008c2ecf20Sopenharmony_ci int i; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci for (i = 0; i != num_configs; ++i) { 4038c2ecf20Sopenharmony_ci imx1_write_bit(ipctl, pin_id, configs[i] & 0x01, MX1_PUEN); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci dev_dbg(ipctl->dev, "pinconf set pullup pin %s\n", 4068c2ecf20Sopenharmony_ci pin_desc_get(pctldev, pin_id)->name); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic void imx1_pinconf_dbg_show(struct pinctrl_dev *pctldev, 4138c2ecf20Sopenharmony_ci struct seq_file *s, unsigned pin_id) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci unsigned long config; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci imx1_pinconf_get(pctldev, pin_id, &config); 4188c2ecf20Sopenharmony_ci seq_printf(s, "0x%lx", config); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void imx1_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, 4228c2ecf20Sopenharmony_ci struct seq_file *s, unsigned group) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 4258c2ecf20Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 4268c2ecf20Sopenharmony_ci struct imx1_pin_group *grp; 4278c2ecf20Sopenharmony_ci unsigned long config; 4288c2ecf20Sopenharmony_ci const char *name; 4298c2ecf20Sopenharmony_ci int i, ret; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (group >= info->ngroups) 4328c2ecf20Sopenharmony_ci return; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci seq_puts(s, "\n"); 4358c2ecf20Sopenharmony_ci grp = &info->groups[group]; 4368c2ecf20Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 4378c2ecf20Sopenharmony_ci name = pin_get_name(pctldev, grp->pins[i].pin_id); 4388c2ecf20Sopenharmony_ci ret = imx1_pinconf_get(pctldev, grp->pins[i].pin_id, &config); 4398c2ecf20Sopenharmony_ci if (ret) 4408c2ecf20Sopenharmony_ci return; 4418c2ecf20Sopenharmony_ci seq_printf(s, "%s: 0x%lx", name, config); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic const struct pinconf_ops imx1_pinconf_ops = { 4468c2ecf20Sopenharmony_ci .pin_config_get = imx1_pinconf_get, 4478c2ecf20Sopenharmony_ci .pin_config_set = imx1_pinconf_set, 4488c2ecf20Sopenharmony_ci .pin_config_dbg_show = imx1_pinconf_dbg_show, 4498c2ecf20Sopenharmony_ci .pin_config_group_dbg_show = imx1_pinconf_group_dbg_show, 4508c2ecf20Sopenharmony_ci}; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic struct pinctrl_desc imx1_pinctrl_desc = { 4538c2ecf20Sopenharmony_ci .pctlops = &imx1_pctrl_ops, 4548c2ecf20Sopenharmony_ci .pmxops = &imx1_pmx_ops, 4558c2ecf20Sopenharmony_ci .confops = &imx1_pinconf_ops, 4568c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4578c2ecf20Sopenharmony_ci}; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int imx1_pinctrl_parse_groups(struct device_node *np, 4608c2ecf20Sopenharmony_ci struct imx1_pin_group *grp, 4618c2ecf20Sopenharmony_ci struct imx1_pinctrl_soc_info *info, 4628c2ecf20Sopenharmony_ci u32 index) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci int size; 4658c2ecf20Sopenharmony_ci const __be32 *list; 4668c2ecf20Sopenharmony_ci int i; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci dev_dbg(info->dev, "group(%d): %pOFn\n", index, np); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* Initialise group */ 4718c2ecf20Sopenharmony_ci grp->name = np->name; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* 4748c2ecf20Sopenharmony_ci * the binding format is fsl,pins = <PIN MUX_ID CONFIG> 4758c2ecf20Sopenharmony_ci */ 4768c2ecf20Sopenharmony_ci list = of_get_property(np, "fsl,pins", &size); 4778c2ecf20Sopenharmony_ci /* we do not check return since it's safe node passed down */ 4788c2ecf20Sopenharmony_ci if (!size || size % 12) { 4798c2ecf20Sopenharmony_ci dev_notice(info->dev, "Not a valid fsl,pins property (%pOFn)\n", 4808c2ecf20Sopenharmony_ci np); 4818c2ecf20Sopenharmony_ci return -EINVAL; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci grp->npins = size / 12; 4858c2ecf20Sopenharmony_ci grp->pins = devm_kcalloc(info->dev, 4868c2ecf20Sopenharmony_ci grp->npins, sizeof(struct imx1_pin), GFP_KERNEL); 4878c2ecf20Sopenharmony_ci grp->pin_ids = devm_kcalloc(info->dev, 4888c2ecf20Sopenharmony_ci grp->npins, sizeof(unsigned int), GFP_KERNEL); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!grp->pins || !grp->pin_ids) 4918c2ecf20Sopenharmony_ci return -ENOMEM; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 4948c2ecf20Sopenharmony_ci grp->pins[i].pin_id = be32_to_cpu(*list++); 4958c2ecf20Sopenharmony_ci grp->pins[i].mux_id = be32_to_cpu(*list++); 4968c2ecf20Sopenharmony_ci grp->pins[i].config = be32_to_cpu(*list++); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci grp->pin_ids[i] = grp->pins[i].pin_id; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic int imx1_pinctrl_parse_functions(struct device_node *np, 5058c2ecf20Sopenharmony_ci struct imx1_pinctrl_soc_info *info, 5068c2ecf20Sopenharmony_ci u32 index) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct device_node *child; 5098c2ecf20Sopenharmony_ci struct imx1_pmx_func *func; 5108c2ecf20Sopenharmony_ci struct imx1_pin_group *grp; 5118c2ecf20Sopenharmony_ci int ret; 5128c2ecf20Sopenharmony_ci static u32 grp_index; 5138c2ecf20Sopenharmony_ci u32 i = 0; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci dev_dbg(info->dev, "parse function(%d): %pOFn\n", index, np); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci func = &info->functions[index]; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* Initialise function */ 5208c2ecf20Sopenharmony_ci func->name = np->name; 5218c2ecf20Sopenharmony_ci func->num_groups = of_get_child_count(np); 5228c2ecf20Sopenharmony_ci if (func->num_groups == 0) 5238c2ecf20Sopenharmony_ci return -EINVAL; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci func->groups = devm_kcalloc(info->dev, 5268c2ecf20Sopenharmony_ci func->num_groups, sizeof(char *), GFP_KERNEL); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (!func->groups) 5298c2ecf20Sopenharmony_ci return -ENOMEM; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 5328c2ecf20Sopenharmony_ci func->groups[i] = child->name; 5338c2ecf20Sopenharmony_ci grp = &info->groups[grp_index++]; 5348c2ecf20Sopenharmony_ci ret = imx1_pinctrl_parse_groups(child, grp, info, i++); 5358c2ecf20Sopenharmony_ci if (ret == -ENOMEM) { 5368c2ecf20Sopenharmony_ci of_node_put(child); 5378c2ecf20Sopenharmony_ci return ret; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci return 0; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic int imx1_pinctrl_parse_dt(struct platform_device *pdev, 5458c2ecf20Sopenharmony_ci struct imx1_pinctrl *pctl, struct imx1_pinctrl_soc_info *info) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 5488c2ecf20Sopenharmony_ci struct device_node *child; 5498c2ecf20Sopenharmony_ci int ret; 5508c2ecf20Sopenharmony_ci u32 nfuncs = 0; 5518c2ecf20Sopenharmony_ci u32 ngroups = 0; 5528c2ecf20Sopenharmony_ci u32 ifunc = 0; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (!np) 5558c2ecf20Sopenharmony_ci return -ENODEV; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 5588c2ecf20Sopenharmony_ci ++nfuncs; 5598c2ecf20Sopenharmony_ci ngroups += of_get_child_count(child); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (!nfuncs) { 5638c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "No pin functions defined\n"); 5648c2ecf20Sopenharmony_ci return -EINVAL; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci info->nfunctions = nfuncs; 5688c2ecf20Sopenharmony_ci info->functions = devm_kcalloc(&pdev->dev, 5698c2ecf20Sopenharmony_ci nfuncs, sizeof(struct imx1_pmx_func), GFP_KERNEL); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci info->ngroups = ngroups; 5728c2ecf20Sopenharmony_ci info->groups = devm_kcalloc(&pdev->dev, 5738c2ecf20Sopenharmony_ci ngroups, sizeof(struct imx1_pin_group), GFP_KERNEL); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (!info->functions || !info->groups) 5778c2ecf20Sopenharmony_ci return -ENOMEM; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 5808c2ecf20Sopenharmony_ci ret = imx1_pinctrl_parse_functions(child, info, ifunc++); 5818c2ecf20Sopenharmony_ci if (ret == -ENOMEM) { 5828c2ecf20Sopenharmony_ci of_node_put(child); 5838c2ecf20Sopenharmony_ci return -ENOMEM; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci return 0; 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ciint imx1_pinctrl_core_probe(struct platform_device *pdev, 5918c2ecf20Sopenharmony_ci struct imx1_pinctrl_soc_info *info) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct imx1_pinctrl *ipctl; 5948c2ecf20Sopenharmony_ci struct resource *res; 5958c2ecf20Sopenharmony_ci struct pinctrl_desc *pctl_desc; 5968c2ecf20Sopenharmony_ci int ret; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (!info || !info->pins || !info->npins) { 5998c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "wrong pinctrl info\n"); 6008c2ecf20Sopenharmony_ci return -EINVAL; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci info->dev = &pdev->dev; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* Create state holders etc for this driver */ 6058c2ecf20Sopenharmony_ci ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); 6068c2ecf20Sopenharmony_ci if (!ipctl) 6078c2ecf20Sopenharmony_ci return -ENOMEM; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 6108c2ecf20Sopenharmony_ci if (!res) 6118c2ecf20Sopenharmony_ci return -ENOENT; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci ipctl->base = devm_ioremap(&pdev->dev, res->start, 6148c2ecf20Sopenharmony_ci resource_size(res)); 6158c2ecf20Sopenharmony_ci if (!ipctl->base) 6168c2ecf20Sopenharmony_ci return -ENOMEM; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci pctl_desc = &imx1_pinctrl_desc; 6198c2ecf20Sopenharmony_ci pctl_desc->name = dev_name(&pdev->dev); 6208c2ecf20Sopenharmony_ci pctl_desc->pins = info->pins; 6218c2ecf20Sopenharmony_ci pctl_desc->npins = info->npins; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci ret = imx1_pinctrl_parse_dt(pdev, ipctl, info); 6248c2ecf20Sopenharmony_ci if (ret) { 6258c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "fail to probe dt properties\n"); 6268c2ecf20Sopenharmony_ci return ret; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci ipctl->info = info; 6308c2ecf20Sopenharmony_ci ipctl->dev = info->dev; 6318c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ipctl); 6328c2ecf20Sopenharmony_ci ipctl->pctl = devm_pinctrl_register(&pdev->dev, pctl_desc, ipctl); 6338c2ecf20Sopenharmony_ci if (IS_ERR(ipctl->pctl)) { 6348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); 6358c2ecf20Sopenharmony_ci return PTR_ERR(ipctl->pctl); 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 6398c2ecf20Sopenharmony_ci if (ret) { 6408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to populate subdevices\n"); 6418c2ecf20Sopenharmony_ci return ret; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return 0; 6478c2ecf20Sopenharmony_ci} 648