162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Core driver for the imx pin controller in imx1/21/27 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (C) 2013 Pengutronix 662306a36Sopenharmony_ci// Author: Markus Pargmann <mpa@pengutronix.de> 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// Based on pinctrl-imx.c: 962306a36Sopenharmony_ci// Author: Dong Aisheng <dong.aisheng@linaro.org> 1062306a36Sopenharmony_ci// Copyright (C) 2012 Freescale Semiconductor, Inc. 1162306a36Sopenharmony_ci// Copyright (C) 2012 Linaro Ltd. 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/bitops.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/of_platform.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/seq_file.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/pinctrl/machine.h> 2462306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 2562306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 2662306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "../core.h" 2962306a36Sopenharmony_ci#include "pinctrl-imx1.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct imx1_pinctrl { 3262306a36Sopenharmony_ci struct device *dev; 3362306a36Sopenharmony_ci struct pinctrl_dev *pctl; 3462306a36Sopenharmony_ci void __iomem *base; 3562306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info; 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * MX1 register offsets 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define MX1_DDIR 0x00 4362306a36Sopenharmony_ci#define MX1_OCR 0x04 4462306a36Sopenharmony_ci#define MX1_ICONFA 0x0c 4562306a36Sopenharmony_ci#define MX1_ICONFB 0x14 4662306a36Sopenharmony_ci#define MX1_GIUS 0x20 4762306a36Sopenharmony_ci#define MX1_GPR 0x38 4862306a36Sopenharmony_ci#define MX1_PUEN 0x40 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define MX1_PORT_STRIDE 0x100 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * MUX_ID format defines 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_ci#define MX1_MUX_FUNCTION(val) (BIT(0) & val) 5762306a36Sopenharmony_ci#define MX1_MUX_GPIO(val) ((BIT(1) & val) >> 1) 5862306a36Sopenharmony_ci#define MX1_MUX_DIR(val) ((BIT(2) & val) >> 2) 5962306a36Sopenharmony_ci#define MX1_MUX_OCONF(val) (((BIT(4) | BIT(5)) & val) >> 4) 6062306a36Sopenharmony_ci#define MX1_MUX_ICONFA(val) (((BIT(8) | BIT(9)) & val) >> 8) 6162306a36Sopenharmony_ci#define MX1_MUX_ICONFB(val) (((BIT(10) | BIT(11)) & val) >> 10) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* 6562306a36Sopenharmony_ci * IMX1 IOMUXC manages the pins based on ports. Each port has 32 pins. IOMUX 6662306a36Sopenharmony_ci * control registers are separated into function, output configuration, input 6762306a36Sopenharmony_ci * configuration A, input configuration B, GPIO in use and data direction. 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * Those controls that are represented by 1 bit have a direct mapping between 7062306a36Sopenharmony_ci * bit position and pin id. If they are represented by 2 bit, the lower 16 pins 7162306a36Sopenharmony_ci * are in the first register and the upper 16 pins in the second (next) 7262306a36Sopenharmony_ci * register. pin_id is stored in bit (pin_id%16)*2 and the bit above. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * Calculates the register offset from a pin_id 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_cistatic void __iomem *imx1_mem(struct imx1_pinctrl *ipctl, unsigned int pin_id) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci unsigned int port = pin_id / 32; 8162306a36Sopenharmony_ci return ipctl->base + port * MX1_PORT_STRIDE; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * Write to a register with 2 bits per pin. The function will automatically 8662306a36Sopenharmony_ci * use the next register if the pin is managed in the second register. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic void imx1_write_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, 8962306a36Sopenharmony_ci u32 value, u32 reg_offset) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; 9262306a36Sopenharmony_ci int offset = (pin_id % 16) * 2; /* offset, regardless of register used */ 9362306a36Sopenharmony_ci int mask = ~(0x3 << offset); /* Mask for 2 bits at offset */ 9462306a36Sopenharmony_ci u32 old_val; 9562306a36Sopenharmony_ci u32 new_val; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Use the next register if the pin's port pin number is >=16 */ 9862306a36Sopenharmony_ci if (pin_id % 32 >= 16) 9962306a36Sopenharmony_ci reg += 0x04; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci dev_dbg(ipctl->dev, "write: register 0x%p offset %d value 0x%x\n", 10262306a36Sopenharmony_ci reg, offset, value); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci /* Get current state of pins */ 10562306a36Sopenharmony_ci old_val = readl(reg); 10662306a36Sopenharmony_ci old_val &= mask; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci new_val = value & 0x3; /* Make sure value is really 2 bit */ 10962306a36Sopenharmony_ci new_val <<= offset; 11062306a36Sopenharmony_ci new_val |= old_val;/* Set new state for pin_id */ 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci writel(new_val, reg); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic void imx1_write_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, 11662306a36Sopenharmony_ci u32 value, u32 reg_offset) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; 11962306a36Sopenharmony_ci int offset = pin_id % 32; 12062306a36Sopenharmony_ci int mask = ~BIT_MASK(offset); 12162306a36Sopenharmony_ci u32 old_val; 12262306a36Sopenharmony_ci u32 new_val; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Get current state of pins */ 12562306a36Sopenharmony_ci old_val = readl(reg); 12662306a36Sopenharmony_ci old_val &= mask; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci new_val = value & 0x1; /* Make sure value is really 1 bit */ 12962306a36Sopenharmony_ci new_val <<= offset; 13062306a36Sopenharmony_ci new_val |= old_val;/* Set new state for pin_id */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci writel(new_val, reg); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic int imx1_read_2bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, 13662306a36Sopenharmony_ci u32 reg_offset) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; 13962306a36Sopenharmony_ci int offset = (pin_id % 16) * 2; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* Use the next register if the pin's port pin number is >=16 */ 14262306a36Sopenharmony_ci if (pin_id % 32 >= 16) 14362306a36Sopenharmony_ci reg += 0x04; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return (readl(reg) & (BIT(offset) | BIT(offset+1))) >> offset; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int imx1_read_bit(struct imx1_pinctrl *ipctl, unsigned int pin_id, 14962306a36Sopenharmony_ci u32 reg_offset) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci void __iomem *reg = imx1_mem(ipctl, pin_id) + reg_offset; 15262306a36Sopenharmony_ci int offset = pin_id % 32; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return !!(readl(reg) & BIT(offset)); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic inline const struct imx1_pin_group *imx1_pinctrl_find_group_by_name( 15862306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info, 15962306a36Sopenharmony_ci const char *name) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci const struct imx1_pin_group *grp = NULL; 16262306a36Sopenharmony_ci int i; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci for (i = 0; i < info->ngroups; i++) { 16562306a36Sopenharmony_ci if (!strcmp(info->groups[i].name, name)) { 16662306a36Sopenharmony_ci grp = &info->groups[i]; 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return grp; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int imx1_get_groups_count(struct pinctrl_dev *pctldev) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 17762306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return info->ngroups; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic const char *imx1_get_group_name(struct pinctrl_dev *pctldev, 18362306a36Sopenharmony_ci unsigned selector) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 18662306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci return info->groups[selector].name; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int imx1_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, 19262306a36Sopenharmony_ci const unsigned int **pins, 19362306a36Sopenharmony_ci unsigned *npins) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 19662306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (selector >= info->ngroups) 19962306a36Sopenharmony_ci return -EINVAL; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci *pins = info->groups[selector].pin_ids; 20262306a36Sopenharmony_ci *npins = info->groups[selector].npins; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void imx1_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, 20862306a36Sopenharmony_ci unsigned offset) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci seq_printf(s, "GPIO %d, function %d, direction %d, oconf %d, iconfa %d, iconfb %d", 21362306a36Sopenharmony_ci imx1_read_bit(ipctl, offset, MX1_GIUS), 21462306a36Sopenharmony_ci imx1_read_bit(ipctl, offset, MX1_GPR), 21562306a36Sopenharmony_ci imx1_read_bit(ipctl, offset, MX1_DDIR), 21662306a36Sopenharmony_ci imx1_read_2bit(ipctl, offset, MX1_OCR), 21762306a36Sopenharmony_ci imx1_read_2bit(ipctl, offset, MX1_ICONFA), 21862306a36Sopenharmony_ci imx1_read_2bit(ipctl, offset, MX1_ICONFB)); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int imx1_dt_node_to_map(struct pinctrl_dev *pctldev, 22262306a36Sopenharmony_ci struct device_node *np, 22362306a36Sopenharmony_ci struct pinctrl_map **map, unsigned *num_maps) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 22662306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 22762306a36Sopenharmony_ci const struct imx1_pin_group *grp; 22862306a36Sopenharmony_ci struct pinctrl_map *new_map; 22962306a36Sopenharmony_ci struct device_node *parent; 23062306a36Sopenharmony_ci int map_num = 1; 23162306a36Sopenharmony_ci int i, j; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* 23462306a36Sopenharmony_ci * first find the group of this node and check if we need create 23562306a36Sopenharmony_ci * config maps for pins 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ci grp = imx1_pinctrl_find_group_by_name(info, np->name); 23862306a36Sopenharmony_ci if (!grp) { 23962306a36Sopenharmony_ci dev_err(info->dev, "unable to find group for node %pOFn\n", 24062306a36Sopenharmony_ci np); 24162306a36Sopenharmony_ci return -EINVAL; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci for (i = 0; i < grp->npins; i++) 24562306a36Sopenharmony_ci map_num++; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map), 24862306a36Sopenharmony_ci GFP_KERNEL); 24962306a36Sopenharmony_ci if (!new_map) 25062306a36Sopenharmony_ci return -ENOMEM; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci *map = new_map; 25362306a36Sopenharmony_ci *num_maps = map_num; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* create mux map */ 25662306a36Sopenharmony_ci parent = of_get_parent(np); 25762306a36Sopenharmony_ci if (!parent) { 25862306a36Sopenharmony_ci kfree(new_map); 25962306a36Sopenharmony_ci return -EINVAL; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; 26262306a36Sopenharmony_ci new_map[0].data.mux.function = parent->name; 26362306a36Sopenharmony_ci new_map[0].data.mux.group = np->name; 26462306a36Sopenharmony_ci of_node_put(parent); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* create config map */ 26762306a36Sopenharmony_ci new_map++; 26862306a36Sopenharmony_ci for (i = j = 0; i < grp->npins; i++) { 26962306a36Sopenharmony_ci new_map[j].type = PIN_MAP_TYPE_CONFIGS_PIN; 27062306a36Sopenharmony_ci new_map[j].data.configs.group_or_pin = 27162306a36Sopenharmony_ci pin_get_name(pctldev, grp->pins[i].pin_id); 27262306a36Sopenharmony_ci new_map[j].data.configs.configs = &grp->pins[i].config; 27362306a36Sopenharmony_ci new_map[j].data.configs.num_configs = 1; 27462306a36Sopenharmony_ci j++; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", 27862306a36Sopenharmony_ci (*map)->data.mux.function, (*map)->data.mux.group, map_num); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic void imx1_dt_free_map(struct pinctrl_dev *pctldev, 28462306a36Sopenharmony_ci struct pinctrl_map *map, unsigned num_maps) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci kfree(map); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic const struct pinctrl_ops imx1_pctrl_ops = { 29062306a36Sopenharmony_ci .get_groups_count = imx1_get_groups_count, 29162306a36Sopenharmony_ci .get_group_name = imx1_get_group_name, 29262306a36Sopenharmony_ci .get_group_pins = imx1_get_group_pins, 29362306a36Sopenharmony_ci .pin_dbg_show = imx1_pin_dbg_show, 29462306a36Sopenharmony_ci .dt_node_to_map = imx1_dt_node_to_map, 29562306a36Sopenharmony_ci .dt_free_map = imx1_dt_free_map, 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int imx1_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, 29962306a36Sopenharmony_ci unsigned group) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 30262306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 30362306a36Sopenharmony_ci const struct imx1_pin *pins; 30462306a36Sopenharmony_ci unsigned int npins; 30562306a36Sopenharmony_ci int i; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* 30862306a36Sopenharmony_ci * Configure the mux mode for each pin in the group for a specific 30962306a36Sopenharmony_ci * function. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci pins = info->groups[group].pins; 31262306a36Sopenharmony_ci npins = info->groups[group].npins; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci WARN_ON(!pins || !npins); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci dev_dbg(ipctl->dev, "enable function %s group %s\n", 31762306a36Sopenharmony_ci info->functions[selector].name, info->groups[group].name); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci for (i = 0; i < npins; i++) { 32062306a36Sopenharmony_ci unsigned int mux = pins[i].mux_id; 32162306a36Sopenharmony_ci unsigned int pin_id = pins[i].pin_id; 32262306a36Sopenharmony_ci unsigned int afunction = MX1_MUX_FUNCTION(mux); 32362306a36Sopenharmony_ci unsigned int gpio_in_use = MX1_MUX_GPIO(mux); 32462306a36Sopenharmony_ci unsigned int direction = MX1_MUX_DIR(mux); 32562306a36Sopenharmony_ci unsigned int gpio_oconf = MX1_MUX_OCONF(mux); 32662306a36Sopenharmony_ci unsigned int gpio_iconfa = MX1_MUX_ICONFA(mux); 32762306a36Sopenharmony_ci unsigned int gpio_iconfb = MX1_MUX_ICONFB(mux); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci dev_dbg(pctldev->dev, "%s, pin 0x%x, function %d, gpio %d, direction %d, oconf %d, iconfa %d, iconfb %d\n", 33062306a36Sopenharmony_ci __func__, pin_id, afunction, gpio_in_use, 33162306a36Sopenharmony_ci direction, gpio_oconf, gpio_iconfa, 33262306a36Sopenharmony_ci gpio_iconfb); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci imx1_write_bit(ipctl, pin_id, gpio_in_use, MX1_GIUS); 33562306a36Sopenharmony_ci imx1_write_bit(ipctl, pin_id, direction, MX1_DDIR); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (gpio_in_use) { 33862306a36Sopenharmony_ci imx1_write_2bit(ipctl, pin_id, gpio_oconf, MX1_OCR); 33962306a36Sopenharmony_ci imx1_write_2bit(ipctl, pin_id, gpio_iconfa, 34062306a36Sopenharmony_ci MX1_ICONFA); 34162306a36Sopenharmony_ci imx1_write_2bit(ipctl, pin_id, gpio_iconfb, 34262306a36Sopenharmony_ci MX1_ICONFB); 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci imx1_write_bit(ipctl, pin_id, afunction, MX1_GPR); 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int imx1_pmx_get_funcs_count(struct pinctrl_dev *pctldev) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 35462306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return info->nfunctions; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic const char *imx1_pmx_get_func_name(struct pinctrl_dev *pctldev, 36062306a36Sopenharmony_ci unsigned selector) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 36362306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return info->functions[selector].name; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int imx1_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, 36962306a36Sopenharmony_ci const char * const **groups, 37062306a36Sopenharmony_ci unsigned * const num_groups) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 37362306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci *groups = info->functions[selector].groups; 37662306a36Sopenharmony_ci *num_groups = info->functions[selector].num_groups; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic const struct pinmux_ops imx1_pmx_ops = { 38262306a36Sopenharmony_ci .get_functions_count = imx1_pmx_get_funcs_count, 38362306a36Sopenharmony_ci .get_function_name = imx1_pmx_get_func_name, 38462306a36Sopenharmony_ci .get_function_groups = imx1_pmx_get_groups, 38562306a36Sopenharmony_ci .set_mux = imx1_pmx_set, 38662306a36Sopenharmony_ci}; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int imx1_pinconf_get(struct pinctrl_dev *pctldev, 38962306a36Sopenharmony_ci unsigned pin_id, unsigned long *config) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci *config = imx1_read_bit(ipctl, pin_id, MX1_PUEN); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci return 0; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int imx1_pinconf_set(struct pinctrl_dev *pctldev, 39962306a36Sopenharmony_ci unsigned pin_id, unsigned long *configs, 40062306a36Sopenharmony_ci unsigned num_configs) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 40362306a36Sopenharmony_ci int i; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci for (i = 0; i != num_configs; ++i) { 40662306a36Sopenharmony_ci imx1_write_bit(ipctl, pin_id, configs[i] & 0x01, MX1_PUEN); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci dev_dbg(ipctl->dev, "pinconf set pullup pin %s\n", 40962306a36Sopenharmony_ci pin_desc_get(pctldev, pin_id)->name); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void imx1_pinconf_dbg_show(struct pinctrl_dev *pctldev, 41662306a36Sopenharmony_ci struct seq_file *s, unsigned pin_id) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci unsigned long config; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci imx1_pinconf_get(pctldev, pin_id, &config); 42162306a36Sopenharmony_ci seq_printf(s, "0x%lx", config); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic void imx1_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, 42562306a36Sopenharmony_ci struct seq_file *s, unsigned group) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct imx1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 42862306a36Sopenharmony_ci const struct imx1_pinctrl_soc_info *info = ipctl->info; 42962306a36Sopenharmony_ci struct imx1_pin_group *grp; 43062306a36Sopenharmony_ci unsigned long config; 43162306a36Sopenharmony_ci const char *name; 43262306a36Sopenharmony_ci int i, ret; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (group >= info->ngroups) 43562306a36Sopenharmony_ci return; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci seq_puts(s, "\n"); 43862306a36Sopenharmony_ci grp = &info->groups[group]; 43962306a36Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 44062306a36Sopenharmony_ci name = pin_get_name(pctldev, grp->pins[i].pin_id); 44162306a36Sopenharmony_ci ret = imx1_pinconf_get(pctldev, grp->pins[i].pin_id, &config); 44262306a36Sopenharmony_ci if (ret) 44362306a36Sopenharmony_ci return; 44462306a36Sopenharmony_ci seq_printf(s, "%s: 0x%lx", name, config); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic const struct pinconf_ops imx1_pinconf_ops = { 44962306a36Sopenharmony_ci .pin_config_get = imx1_pinconf_get, 45062306a36Sopenharmony_ci .pin_config_set = imx1_pinconf_set, 45162306a36Sopenharmony_ci .pin_config_dbg_show = imx1_pinconf_dbg_show, 45262306a36Sopenharmony_ci .pin_config_group_dbg_show = imx1_pinconf_group_dbg_show, 45362306a36Sopenharmony_ci}; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic struct pinctrl_desc imx1_pinctrl_desc = { 45662306a36Sopenharmony_ci .pctlops = &imx1_pctrl_ops, 45762306a36Sopenharmony_ci .pmxops = &imx1_pmx_ops, 45862306a36Sopenharmony_ci .confops = &imx1_pinconf_ops, 45962306a36Sopenharmony_ci .owner = THIS_MODULE, 46062306a36Sopenharmony_ci}; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int imx1_pinctrl_parse_groups(struct device_node *np, 46362306a36Sopenharmony_ci struct imx1_pin_group *grp, 46462306a36Sopenharmony_ci struct imx1_pinctrl_soc_info *info, 46562306a36Sopenharmony_ci u32 index) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci int size; 46862306a36Sopenharmony_ci const __be32 *list; 46962306a36Sopenharmony_ci int i; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci dev_dbg(info->dev, "group(%d): %pOFn\n", index, np); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* Initialise group */ 47462306a36Sopenharmony_ci grp->name = np->name; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* 47762306a36Sopenharmony_ci * the binding format is fsl,pins = <PIN MUX_ID CONFIG> 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ci list = of_get_property(np, "fsl,pins", &size); 48062306a36Sopenharmony_ci /* we do not check return since it's safe node passed down */ 48162306a36Sopenharmony_ci if (!size || size % 12) { 48262306a36Sopenharmony_ci dev_notice(info->dev, "Not a valid fsl,pins property (%pOFn)\n", 48362306a36Sopenharmony_ci np); 48462306a36Sopenharmony_ci return -EINVAL; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci grp->npins = size / 12; 48862306a36Sopenharmony_ci grp->pins = devm_kcalloc(info->dev, 48962306a36Sopenharmony_ci grp->npins, sizeof(struct imx1_pin), GFP_KERNEL); 49062306a36Sopenharmony_ci grp->pin_ids = devm_kcalloc(info->dev, 49162306a36Sopenharmony_ci grp->npins, sizeof(unsigned int), GFP_KERNEL); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!grp->pins || !grp->pin_ids) 49462306a36Sopenharmony_ci return -ENOMEM; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 49762306a36Sopenharmony_ci grp->pins[i].pin_id = be32_to_cpu(*list++); 49862306a36Sopenharmony_ci grp->pins[i].mux_id = be32_to_cpu(*list++); 49962306a36Sopenharmony_ci grp->pins[i].config = be32_to_cpu(*list++); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci grp->pin_ids[i] = grp->pins[i].pin_id; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci return 0; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic int imx1_pinctrl_parse_functions(struct device_node *np, 50862306a36Sopenharmony_ci struct imx1_pinctrl_soc_info *info, 50962306a36Sopenharmony_ci u32 index) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct device_node *child; 51262306a36Sopenharmony_ci struct imx1_pmx_func *func; 51362306a36Sopenharmony_ci struct imx1_pin_group *grp; 51462306a36Sopenharmony_ci int ret; 51562306a36Sopenharmony_ci static u32 grp_index; 51662306a36Sopenharmony_ci u32 i = 0; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci dev_dbg(info->dev, "parse function(%d): %pOFn\n", index, np); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci func = &info->functions[index]; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Initialise function */ 52362306a36Sopenharmony_ci func->name = np->name; 52462306a36Sopenharmony_ci func->num_groups = of_get_child_count(np); 52562306a36Sopenharmony_ci if (func->num_groups == 0) 52662306a36Sopenharmony_ci return -EINVAL; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci func->groups = devm_kcalloc(info->dev, 52962306a36Sopenharmony_ci func->num_groups, sizeof(char *), GFP_KERNEL); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (!func->groups) 53262306a36Sopenharmony_ci return -ENOMEM; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci for_each_child_of_node(np, child) { 53562306a36Sopenharmony_ci func->groups[i] = child->name; 53662306a36Sopenharmony_ci grp = &info->groups[grp_index++]; 53762306a36Sopenharmony_ci ret = imx1_pinctrl_parse_groups(child, grp, info, i++); 53862306a36Sopenharmony_ci if (ret == -ENOMEM) { 53962306a36Sopenharmony_ci of_node_put(child); 54062306a36Sopenharmony_ci return ret; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic int imx1_pinctrl_parse_dt(struct platform_device *pdev, 54862306a36Sopenharmony_ci struct imx1_pinctrl *pctl, struct imx1_pinctrl_soc_info *info) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 55162306a36Sopenharmony_ci struct device_node *child; 55262306a36Sopenharmony_ci int ret; 55362306a36Sopenharmony_ci u32 nfuncs = 0; 55462306a36Sopenharmony_ci u32 ngroups = 0; 55562306a36Sopenharmony_ci u32 ifunc = 0; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (!np) 55862306a36Sopenharmony_ci return -ENODEV; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci for_each_child_of_node(np, child) { 56162306a36Sopenharmony_ci ++nfuncs; 56262306a36Sopenharmony_ci ngroups += of_get_child_count(child); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (!nfuncs) { 56662306a36Sopenharmony_ci dev_err(&pdev->dev, "No pin functions defined\n"); 56762306a36Sopenharmony_ci return -EINVAL; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci info->nfunctions = nfuncs; 57162306a36Sopenharmony_ci info->functions = devm_kcalloc(&pdev->dev, 57262306a36Sopenharmony_ci nfuncs, sizeof(struct imx1_pmx_func), GFP_KERNEL); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci info->ngroups = ngroups; 57562306a36Sopenharmony_ci info->groups = devm_kcalloc(&pdev->dev, 57662306a36Sopenharmony_ci ngroups, sizeof(struct imx1_pin_group), GFP_KERNEL); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (!info->functions || !info->groups) 58062306a36Sopenharmony_ci return -ENOMEM; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci for_each_child_of_node(np, child) { 58362306a36Sopenharmony_ci ret = imx1_pinctrl_parse_functions(child, info, ifunc++); 58462306a36Sopenharmony_ci if (ret == -ENOMEM) { 58562306a36Sopenharmony_ci of_node_put(child); 58662306a36Sopenharmony_ci return -ENOMEM; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ciint imx1_pinctrl_core_probe(struct platform_device *pdev, 59462306a36Sopenharmony_ci struct imx1_pinctrl_soc_info *info) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct imx1_pinctrl *ipctl; 59762306a36Sopenharmony_ci struct resource *res; 59862306a36Sopenharmony_ci struct pinctrl_desc *pctl_desc; 59962306a36Sopenharmony_ci int ret; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (!info || !info->pins || !info->npins) { 60262306a36Sopenharmony_ci dev_err(&pdev->dev, "wrong pinctrl info\n"); 60362306a36Sopenharmony_ci return -EINVAL; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci info->dev = &pdev->dev; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* Create state holders etc for this driver */ 60862306a36Sopenharmony_ci ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); 60962306a36Sopenharmony_ci if (!ipctl) 61062306a36Sopenharmony_ci return -ENOMEM; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 61362306a36Sopenharmony_ci if (!res) 61462306a36Sopenharmony_ci return -ENOENT; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci ipctl->base = devm_ioremap(&pdev->dev, res->start, 61762306a36Sopenharmony_ci resource_size(res)); 61862306a36Sopenharmony_ci if (!ipctl->base) 61962306a36Sopenharmony_ci return -ENOMEM; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci pctl_desc = &imx1_pinctrl_desc; 62262306a36Sopenharmony_ci pctl_desc->name = dev_name(&pdev->dev); 62362306a36Sopenharmony_ci pctl_desc->pins = info->pins; 62462306a36Sopenharmony_ci pctl_desc->npins = info->npins; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci ret = imx1_pinctrl_parse_dt(pdev, ipctl, info); 62762306a36Sopenharmony_ci if (ret) { 62862306a36Sopenharmony_ci dev_err(&pdev->dev, "fail to probe dt properties\n"); 62962306a36Sopenharmony_ci return ret; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci ipctl->info = info; 63362306a36Sopenharmony_ci ipctl->dev = info->dev; 63462306a36Sopenharmony_ci platform_set_drvdata(pdev, ipctl); 63562306a36Sopenharmony_ci ipctl->pctl = devm_pinctrl_register(&pdev->dev, pctl_desc, ipctl); 63662306a36Sopenharmony_ci if (IS_ERR(ipctl->pctl)) { 63762306a36Sopenharmony_ci dev_err(&pdev->dev, "could not register IMX pinctrl driver\n"); 63862306a36Sopenharmony_ci return PTR_ERR(ipctl->pctl); 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 64262306a36Sopenharmony_ci if (ret) { 64362306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to populate subdevices\n"); 64462306a36Sopenharmony_ci return ret; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci dev_info(&pdev->dev, "initialized IMX pinctrl driver\n"); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return 0; 65062306a36Sopenharmony_ci} 651