1f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* 2f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * pin-controller/pin-mux/pin-config/gpio-driver for Samsung's EXYNOS5440 SoC. 3f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * 4f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * Copyright (c) 2012 Samsung Electronics Co., Ltd. 5f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * http://www.samsung.com 6f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * 7f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * This program is free software; you can redistribute it and/or modify 8f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * it under the terms of the GNU General Public License as published by 9f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * the Free Software Foundation; either version 2 of the License, or 10f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * (at your option) any later version. 11f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 12f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 13f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/module.h> 14f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/platform_device.h> 15f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/io.h> 16f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/slab.h> 17f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/err.h> 18f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/gpio.h> 19f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/device.h> 20f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/pinctrl/pinctrl.h> 21f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/pinctrl/pinmux.h> 22f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#include <linux/pinctrl/pinconf.h> 238dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham#include <linux/interrupt.h> 248dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham#include <linux/irqdomain.h> 258dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham#include <linux/of_irq.h> 26ebe629a39e04db3fe876d34833a2d8a6a6d4c134Sachin Kamat#include "../core.h" 27f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 28f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* EXYNOS5440 GPIO and Pinctrl register offsets */ 29f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_MUX 0x00 30f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_IE 0x04 31f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_INT 0x08 32f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_TYPE 0x0C 33f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_VAL 0x10 34f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_OE 0x14 35f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_IN 0x18 36f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_PE 0x1C 37f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_PS 0x20 38f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_SR 0x24 39f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_DS0 0x28 40f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GPIO_DS1 0x2C 41f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 42f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define EXYNOS5440_MAX_PINS 23 438dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham#define EXYNOS5440_MAX_GPIO_INT 8 44f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PIN_NAME_LENGTH 10 45f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 46f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GROUP_SUFFIX "-grp" 47f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define GSUFFIX_LEN sizeof(GROUP_SUFFIX) 48f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define FUNCTION_SUFFIX "-mux" 49f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) 50f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 51f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* 52f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * pin configuration type and its value are packed together into a 16-bits. 53f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * The upper 8-bits represent the configuration type and the lower 8-bits 54f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * hold the value of the configuration type. 55f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 56f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_TYPE_MASK 0xFF 57f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_VALUE_SHIFT 8 58f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_VALUE_MASK (0xFF << PINCFG_VALUE_SHIFT) 59f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_PACK(type, value) (((value) << PINCFG_VALUE_SHIFT) | type) 60f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_UNPACK_TYPE(cfg) ((cfg) & PINCFG_TYPE_MASK) 61f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham#define PINCFG_UNPACK_VALUE(cfg) (((cfg) & PINCFG_VALUE_MASK) >> \ 62f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham PINCFG_VALUE_SHIFT) 63f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 64f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/** 65f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * enum pincfg_type - possible pin configuration types supported. 66f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @PINCFG_TYPE_PUD: Pull up/down configuration. 67f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @PINCFG_TYPE_DRV: Drive strength configuration. 68f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @PINCFG_TYPE_SKEW_RATE: Skew rate configuration. 69f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @PINCFG_TYPE_INPUT_TYPE: Pin input type configuration. 70f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 71f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamenum pincfg_type { 72f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham PINCFG_TYPE_PUD, 73f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham PINCFG_TYPE_DRV, 74f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham PINCFG_TYPE_SKEW_RATE, 75f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham PINCFG_TYPE_INPUT_TYPE 76f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 77f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 78f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/** 79f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * struct exynos5440_pin_group: represent group of pins for pincfg setting. 80f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @name: name of the pin group, used to lookup the group. 81f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @pins: the pins included in this group. 82f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @num_pins: number of pins included in this group. 83f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 84f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstruct exynos5440_pin_group { 85f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham const char *name; 86f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham const unsigned int *pins; 87f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u8 num_pins; 88f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 89f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 90f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/** 91f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * struct exynos5440_pmx_func: represent a pin function. 92f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @name: name of the pin function, used to lookup the function. 93f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @groups: one or more names of pin groups that provide this function. 94f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @num_groups: number of groups included in @groups. 95f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @function: the function number to be programmed when selected. 96f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 97f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstruct exynos5440_pmx_func { 98f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham const char *name; 99f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham const char **groups; 100f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u8 num_groups; 101f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned long function; 102f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 103f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 104f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/** 105f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * struct exynos5440_pinctrl_priv_data: driver's private runtime data. 106f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @reg_base: ioremapped based address of the register space. 107f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @gc: gpio chip registered with gpiolib. 108f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @pin_groups: list of pin groups parsed from device tree. 109f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @nr_groups: number of pin groups available. 110f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @pmx_functions: list of pin functions parsed from device tree. 111f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * @nr_functions: number of pin functions available. 112f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 113f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstruct exynos5440_pinctrl_priv_data { 114f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham void __iomem *reg_base; 115f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct gpio_chip *gc; 1168dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct irq_domain *irq_domain; 117f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 118f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham const struct exynos5440_pin_group *pin_groups; 119f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned int nr_groups; 120f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham const struct exynos5440_pmx_func *pmx_functions; 121f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned int nr_functions; 122f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 123f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1248dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/** 1258dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham * struct exynos5440_gpio_intr_data: private data for gpio interrupts. 1268dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham * @priv: driver's private runtime data. 1278dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham * @gpio_int: gpio interrupt number. 1288dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham */ 1298dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstruct exynos5440_gpio_intr_data { 1308dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct exynos5440_pinctrl_priv_data *priv; 1318dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham unsigned int gpio_int; 1328dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham}; 1338dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 134f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* list of all possible config options supported */ 135d5fd5da290cef159be1295c162b4c71b8c1971a2Axel Linstatic struct pin_config { 136f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham char *prop_cfg; 137f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned int cfg_type; 138f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} pcfgs[] = { 139f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham { "samsung,exynos5440-pin-pud", PINCFG_TYPE_PUD }, 140f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham { "samsung,exynos5440-pin-drv", PINCFG_TYPE_DRV }, 141f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham { "samsung,exynos5440-pin-skew-rate", PINCFG_TYPE_SKEW_RATE }, 142f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham { "samsung,exynos5440-pin-input-type", PINCFG_TYPE_INPUT_TYPE }, 143f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 144f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 145f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* check if the selector is a valid pin group selector */ 146f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_get_group_count(struct pinctrl_dev *pctldev) 147f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 148f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 149f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 150f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 151f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return priv->nr_groups; 152f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 153f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 154f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* return the name of the group selected by the group selector */ 155f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic const char *exynos5440_get_group_name(struct pinctrl_dev *pctldev, 156f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned selector) 157f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 158f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 159f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 160f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 161f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return priv->pin_groups[selector].name; 162f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 163f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 164f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* return the pin numbers associated with the specified group */ 165f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_get_group_pins(struct pinctrl_dev *pctldev, 166f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned selector, const unsigned **pins, unsigned *num_pins) 167f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 168f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 169f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 170f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 171f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *pins = priv->pin_groups[selector].pins; 172f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *num_pins = priv->pin_groups[selector].num_pins; 173f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 174f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 175f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 176f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* create pinctrl_map entries by parsing device tree nodes */ 177f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, 178f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct device_node *np, struct pinctrl_map **maps, 179f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned *nmaps) 180f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 181f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct device *dev = pctldev->dev; 182f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct pinctrl_map *map; 183f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned long *cfg = NULL; 184f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham char *gname, *fname; 185f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham int cfg_cnt = 0, map_cnt = 0, idx = 0; 186f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 187f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* count the number of config options specfied in the node */ 188f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham for (idx = 0; idx < ARRAY_SIZE(pcfgs); idx++) 189f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (of_find_property(np, pcfgs[idx].prop_cfg, NULL)) 190f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham cfg_cnt++; 191f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 192f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* 193f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * Find out the number of map entries to create. All the config options 194f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * can be accomadated into a single config map entry. 195f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 196f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (cfg_cnt) 197f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map_cnt = 1; 198f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) 199f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map_cnt++; 200f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!map_cnt) { 201f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "node %s does not have either config or function " 202f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham "configurations\n", np->name); 203f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -EINVAL; 204f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 205f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 206f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* Allocate memory for pin-map entries */ 207f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); 208f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!map) { 209f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "could not alloc memory for pin-maps\n"); 210f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 211f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 212f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *nmaps = 0; 213f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 214f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* 215f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * Allocate memory for pin group name. The pin group name is derived 216f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * from the node name from which these map entries are be created. 217f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 218f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); 219f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!gname) { 220f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "failed to alloc memory for group name\n"); 221f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham goto free_map; 222f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 22379bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham snprintf(gname, strlen(np->name) + 4, "%s%s", np->name, GROUP_SUFFIX); 224f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 225f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* 226f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * don't have config options? then skip over to creating function 227f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * map entries. 228f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 229f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!cfg_cnt) 230f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham goto skip_cfgs; 231f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 232f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* Allocate memory for config entries */ 233f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); 234f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!cfg) { 235f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "failed to alloc memory for configs\n"); 236f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham goto free_gname; 237f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 238f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 239f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* Prepare a list of config settings */ 240f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { 241f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 value; 242f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!of_property_read_u32(np, pcfgs[idx].prop_cfg, &value)) 243f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham cfg[cfg_cnt++] = 244f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham PINCFG_PACK(pcfgs[idx].cfg_type, value); 245f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 246f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 247f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* create the config map entry */ 248f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map[*nmaps].data.configs.group_or_pin = gname; 249f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map[*nmaps].data.configs.configs = cfg; 250f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map[*nmaps].data.configs.num_configs = cfg_cnt; 251f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map[*nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP; 252f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *nmaps += 1; 253f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 254f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamskip_cfgs: 255f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* create the function map entry */ 256f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) { 257f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); 258f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!fname) { 259f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "failed to alloc memory for func name\n"); 260f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham goto free_cfg; 261f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 26279bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham snprintf(fname, strlen(np->name) + 4, "%s%s", np->name, 26379bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham FUNCTION_SUFFIX); 264f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 265f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map[*nmaps].data.mux.group = gname; 266f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map[*nmaps].data.mux.function = fname; 267f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham map[*nmaps].type = PIN_MAP_TYPE_MUX_GROUP; 268f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *nmaps += 1; 269f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 270f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 271f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *maps = map; 272f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 273f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 274f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamfree_cfg: 275f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham kfree(cfg); 276f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamfree_gname: 277f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham kfree(gname); 278f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamfree_map: 279f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham kfree(map); 280f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 281f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 282f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 283f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* free the memory allocated to hold the pin-map table */ 284f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic void exynos5440_dt_free_map(struct pinctrl_dev *pctldev, 285f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct pinctrl_map *map, unsigned num_maps) 286f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 287f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham int idx; 288f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 289f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham for (idx = 0; idx < num_maps; idx++) { 290f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (map[idx].type == PIN_MAP_TYPE_MUX_GROUP) { 291f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham kfree(map[idx].data.mux.function); 292f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!idx) 293f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham kfree(map[idx].data.mux.group); 294f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } else if (map->type == PIN_MAP_TYPE_CONFIGS_GROUP) { 295f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham kfree(map[idx].data.configs.configs); 296f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!idx) 297f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham kfree(map[idx].data.configs.group_or_pin); 298f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 299f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham }; 300f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 301f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham kfree(map); 302f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 303f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 304f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* list of pinctrl callbacks for the pinctrl core */ 305022ab148d28e8466e45d28552224e3029f1cccd8Laurent Pinchartstatic const struct pinctrl_ops exynos5440_pctrl_ops = { 306f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .get_groups_count = exynos5440_get_group_count, 307f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .get_group_name = exynos5440_get_group_name, 308f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .get_group_pins = exynos5440_get_group_pins, 309f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .dt_node_to_map = exynos5440_dt_node_to_map, 310f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .dt_free_map = exynos5440_dt_free_map, 311f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 312f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 313f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* check if the selector is a valid pin function selector */ 314f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_get_functions_count(struct pinctrl_dev *pctldev) 315f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 316f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 317f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 318f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 319f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return priv->nr_functions; 320f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 321f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 322f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* return the name of the pin function specified */ 323f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic const char *exynos5440_pinmux_get_fname(struct pinctrl_dev *pctldev, 324f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned selector) 325f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 326f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 327f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 328f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 329f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return priv->pmx_functions[selector].name; 330f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 331f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 332f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* return the groups associated for the specified function selector */ 333f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinmux_get_groups(struct pinctrl_dev *pctldev, 334f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned selector, const char * const **groups, 335f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned * const num_groups) 336f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 337f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 338f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 339f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 340f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *groups = priv->pmx_functions[selector].groups; 341f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *num_groups = priv->pmx_functions[selector].num_groups; 342f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 343f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 344f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 345f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* enable or disable a pinmux function */ 346f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic void exynos5440_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, 347f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned group, bool enable) 348f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 349f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 350f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham void __iomem *base; 351f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 function; 352f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 data; 353f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 354f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 355f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham base = priv->reg_base; 356f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham function = priv->pmx_functions[selector].function; 357f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 358f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_MUX); 359f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (enable) 360f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data |= (1 << function); 361f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham else 362f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data &= ~(1 << function); 363f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham writel(data, base + GPIO_MUX); 364f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 365f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 366f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* enable a specified pinmux by writing to registers */ 36703e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleijstatic int exynos5440_pinmux_set_mux(struct pinctrl_dev *pctldev, 36803e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij unsigned selector, 36903e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij unsigned group) 370f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 371f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham exynos5440_pinmux_setup(pctldev, selector, group, true); 372f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 373f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 374f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 375f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* 376f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * The calls to gpio_direction_output() and gpio_direction_input() 377f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * leads to this function call (via the pinctrl_gpio_direction_{input|output}() 378f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * function called from the gpiolib interface). 379f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 380f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, 381f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct pinctrl_gpio_range *range, unsigned offset, bool input) 382f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 383f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 384f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 385f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 386f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* list of pinmux callbacks for the pinmux vertical in pinctrl core */ 387022ab148d28e8466e45d28552224e3029f1cccd8Laurent Pinchartstatic const struct pinmux_ops exynos5440_pinmux_ops = { 388f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .get_functions_count = exynos5440_get_functions_count, 389f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .get_function_name = exynos5440_pinmux_get_fname, 390f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .get_function_groups = exynos5440_pinmux_get_groups, 39103e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij .set_mux = exynos5440_pinmux_set_mux, 392f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .gpio_set_direction = exynos5440_pinmux_gpio_set_direction, 393f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 394f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 395f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* set the pin config settings for a specified pin */ 396f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 39703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin unsigned long *configs, 39803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin unsigned num_configs) 399f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 400f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 401f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham void __iomem *base; 40203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin enum pincfg_type cfg_type; 40303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin u32 cfg_value; 404f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 data; 40503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin int i; 406f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 407f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 408f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham base = priv->reg_base; 409f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 41003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin for (i = 0; i < num_configs; i++) { 41103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin cfg_type = PINCFG_UNPACK_TYPE(configs[i]); 41203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin cfg_value = PINCFG_UNPACK_VALUE(configs[i]); 41303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin 41403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin switch (cfg_type) { 41503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin case PINCFG_TYPE_PUD: 41603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin /* first set pull enable/disable bit */ 41703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data = readl(base + GPIO_PE); 41803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data &= ~(1 << pin); 41903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin if (cfg_value) 42003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data |= (1 << pin); 42103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin writel(data, base + GPIO_PE); 42203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin 42303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin /* then set pull up/down bit */ 42403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data = readl(base + GPIO_PS); 42503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data &= ~(1 << pin); 42603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin if (cfg_value == 2) 42703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data |= (1 << pin); 42803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin writel(data, base + GPIO_PS); 42903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin break; 43003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin 43103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin case PINCFG_TYPE_DRV: 43203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin /* set the first bit of the drive strength */ 43303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data = readl(base + GPIO_DS0); 43403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data &= ~(1 << pin); 43503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data |= ((cfg_value & 1) << pin); 43603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin writel(data, base + GPIO_DS0); 43703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin cfg_value >>= 1; 43803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin 43903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin /* set the second bit of the driver strength */ 44003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data = readl(base + GPIO_DS1); 44103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data &= ~(1 << pin); 44203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data |= ((cfg_value & 1) << pin); 44303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin writel(data, base + GPIO_DS1); 44403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin break; 44503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin case PINCFG_TYPE_SKEW_RATE: 44603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data = readl(base + GPIO_SR); 44703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data &= ~(1 << pin); 44803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data |= ((cfg_value & 1) << pin); 44903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin writel(data, base + GPIO_SR); 45003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin break; 45103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin case PINCFG_TYPE_INPUT_TYPE: 45203b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data = readl(base + GPIO_TYPE); 45303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data &= ~(1 << pin); 45403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin data |= ((cfg_value & 1) << pin); 45503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin writel(data, base + GPIO_TYPE); 45603b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin break; 45703b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin default: 45803b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin WARN_ON(1); 45903b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin return -EINVAL; 46003b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin } 46103b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin } /* for each config */ 462f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 463f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 464f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 465f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 466f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* get the pin config settings for a specified pin */ 467f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, 468f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned long *config) 469f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 470f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 471f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham void __iomem *base; 472f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config); 473f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 data; 474f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 475f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 476f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham base = priv->reg_base; 477f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 478f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham switch (cfg_type) { 479f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham case PINCFG_TYPE_PUD: 480f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_PE); 481f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = (data >> pin) & 1; 482f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!data) 483f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *config = 0; 484f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham else 485f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *config = ((readl(base + GPIO_PS) >> pin) & 1) + 1; 486f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham break; 487f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham case PINCFG_TYPE_DRV: 488f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_DS0); 489f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = (data >> pin) & 1; 490f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *config = data; 491f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_DS1); 492f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = (data >> pin) & 1; 493f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *config |= (data << 1); 494f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham break; 495f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham case PINCFG_TYPE_SKEW_RATE: 496f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_SR); 497f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *config = (data >> pin) & 1; 498f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham break; 499f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham case PINCFG_TYPE_INPUT_TYPE: 500f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_TYPE); 501f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *config = (data >> pin) & 1; 502f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham break; 503f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham default: 504f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham WARN_ON(1); 505f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -EINVAL; 506f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 507f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 508f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 509f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 510f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 511f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* set the pin config settings for a specified pin group */ 512f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev, 51303b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin unsigned group, unsigned long *configs, 51403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin unsigned num_configs) 515f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 516f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 517f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham const unsigned int *pins; 518f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned int cnt; 519f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 520f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 521f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pins = priv->pin_groups[group].pins; 522f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 523f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham for (cnt = 0; cnt < priv->pin_groups[group].num_pins; cnt++) 52403b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin exynos5440_pinconf_set(pctldev, pins[cnt], configs, 52503b054e9696c3cbd3d5905ec96da15acd0a2fe8dSherman Yin num_configs); 526f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 527f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 528f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 529f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 530f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* get the pin config settings for a specified pin group */ 531f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_pinconf_group_get(struct pinctrl_dev *pctldev, 532f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned int group, unsigned long *config) 533f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 534f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 535f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham const unsigned int *pins; 536f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 537f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv = pinctrl_dev_get_drvdata(pctldev); 538f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pins = priv->pin_groups[group].pins; 539f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham exynos5440_pinconf_get(pctldev, pins[0], config); 540f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 541f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 542f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 543f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* list of pinconfig callbacks for pinconfig vertical in the pinctrl code */ 544022ab148d28e8466e45d28552224e3029f1cccd8Laurent Pinchartstatic const struct pinconf_ops exynos5440_pinconf_ops = { 545f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .pin_config_get = exynos5440_pinconf_get, 546f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .pin_config_set = exynos5440_pinconf_set, 547f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .pin_config_group_get = exynos5440_pinconf_group_get, 548f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .pin_config_group_set = exynos5440_pinconf_group_set, 549f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 550f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 551f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* gpiolib gpio_set callback function */ 552f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic void exynos5440_gpio_set(struct gpio_chip *gc, unsigned offset, int value) 553f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 554f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); 555f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham void __iomem *base = priv->reg_base; 556f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 data; 557f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 558f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_VAL); 559f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data &= ~(1 << offset); 560f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (value) 561f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data |= 1 << offset; 562f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham writel(data, base + GPIO_VAL); 563f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 564f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 565f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* gpiolib gpio_get callback function */ 566f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_gpio_get(struct gpio_chip *gc, unsigned offset) 567f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 568f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); 569f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham void __iomem *base = priv->reg_base; 570f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 data; 571f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 572f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_IN); 573f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data >>= offset; 574f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data &= 1; 575f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return data; 576f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 577f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 578f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* gpiolib gpio_direction_input callback function */ 579f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_gpio_direction_input(struct gpio_chip *gc, unsigned offset) 580f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 581f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); 582f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham void __iomem *base = priv->reg_base; 583f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 data; 584f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 585f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* first disable the data output enable on this pin */ 586f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_OE); 587f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data &= ~(1 << offset); 588f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham writel(data, base + GPIO_OE); 589f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 590f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* now enable input on this pin */ 591f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_IE); 592f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data |= 1 << offset; 593f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham writel(data, base + GPIO_IE); 594f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 595f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 596f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 597f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* gpiolib gpio_direction_output callback function */ 598f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int exynos5440_gpio_direction_output(struct gpio_chip *gc, unsigned offset, 599f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham int value) 600f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 601f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); 602f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham void __iomem *base = priv->reg_base; 603f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 data; 604f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 605f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham exynos5440_gpio_set(gc, offset, value); 606f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 607f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* first disable the data input enable on this pin */ 608f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_IE); 609f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data &= ~(1 << offset); 610f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham writel(data, base + GPIO_IE); 611f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 612f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* now enable output on this pin */ 613f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data = readl(base + GPIO_OE); 614f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham data |= 1 << offset; 615f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham writel(data, base + GPIO_OE); 616f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 617f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 618f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 6198dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* gpiolib gpio_to_irq callback function */ 6208dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic int exynos5440_gpio_to_irq(struct gpio_chip *gc, unsigned offset) 6218dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{ 6228dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct exynos5440_pinctrl_priv_data *priv = dev_get_drvdata(gc->dev); 6238dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham unsigned int virq; 6248dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 6258dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham if (offset < 16 || offset > 23) 6268dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return -ENXIO; 6278dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 6288dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham if (!priv->irq_domain) 6298dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return -ENXIO; 6308dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 6318dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham virq = irq_create_mapping(priv->irq_domain, offset - 16); 6328dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return virq ? : -ENXIO; 6338dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham} 6348dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 635f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* parse the pin numbers listed in the 'samsung,exynos5440-pins' property */ 636312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev, 637f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct device_node *cfg_np, unsigned int **pin_list, 638f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned int *npins) 639f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 640f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct device *dev = &pdev->dev; 641f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct property *prop; 642f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 643f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham prop = of_find_property(cfg_np, "samsung,exynos5440-pins", NULL); 644f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!prop) 645f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOENT; 646f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 647f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *npins = prop->length / sizeof(unsigned long); 648f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!*npins) { 649f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "invalid pin list in %s node", cfg_np->name); 650f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -EINVAL; 651f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 652f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 653f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); 654f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!*pin_list) { 655f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "failed to allocate memory for pin list\n"); 656f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 657f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 658f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 659f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return of_property_read_u32_array(cfg_np, "samsung,exynos5440-pins", 660f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham *pin_list, *npins); 661f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 662f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 663f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* 664f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * Parse the information about all the available pin groups and pin functions 665f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * from device node of the pin-controller. 666f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 667312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_pinctrl_parse_dt(struct platform_device *pdev, 668f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv) 669f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 670f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct device *dev = &pdev->dev; 671f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct device_node *dev_np = dev->of_node; 672f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct device_node *cfg_np; 673f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pin_group *groups, *grp; 674f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pmx_func *functions, *func; 675f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned *pin_list; 676f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham unsigned int npins, grp_cnt, func_idx = 0; 677f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham char *gname, *fname; 678f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham int ret; 679f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 680f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grp_cnt = of_get_child_count(dev_np); 681f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!grp_cnt) 682f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -EINVAL; 683f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 684f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); 685f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!groups) { 686f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "failed allocate memory for ping group list\n"); 687f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -EINVAL; 688f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 689f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grp = groups; 690f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 691f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); 692f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!functions) { 693f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "failed to allocate memory for function list\n"); 694f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -EINVAL; 695f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 696f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham func = functions; 697f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 698f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* 699f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * Iterate over all the child nodes of the pin controller node 700f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * and create pin groups and pin function lists. 701f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 702f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham for_each_child_of_node(dev_np, cfg_np) { 703f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham u32 function; 704f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 705f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ret = exynos5440_pinctrl_parse_dt_pins(pdev, cfg_np, 706f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham &pin_list, &npins); 707f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham if (ret) { 708f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham gname = NULL; 709f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham goto skip_to_pin_function; 710f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham } 711f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 712f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* derive pin group name from the node name */ 713f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, 714f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham GFP_KERNEL); 715f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!gname) { 716f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "failed to alloc memory for group name\n"); 717f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 718f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 71979bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham snprintf(gname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name, 72079bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham GROUP_SUFFIX); 721f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 722f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grp->name = gname; 723f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grp->pins = pin_list; 724f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grp->num_pins = npins; 725f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grp++; 726f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 727f9819739427e6049d2d318743a4a25817018afd4Thomas Abrahamskip_to_pin_function: 728f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ret = of_property_read_u32(cfg_np, "samsung,exynos5440-pin-function", 729f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham &function); 730f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (ret) 731f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham continue; 732f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 733f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* derive function name from the node name */ 734f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, 735f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham GFP_KERNEL); 736f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!fname) { 737f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "failed to alloc memory for func name\n"); 738f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 739f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 74079bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham snprintf(fname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name, 74179bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham FUNCTION_SUFFIX); 742f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 743f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham func->name = fname; 744f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); 745f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!func->groups) { 746f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "failed to alloc memory for group list " 747f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham "in pin function"); 748f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 749f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 750f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham func->groups[0] = gname; 751f9819739427e6049d2d318743a4a25817018afd4Thomas Abraham func->num_groups = gname ? 1 : 0; 752f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham func->function = function; 753f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham func++; 754f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham func_idx++; 755f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 756f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 757f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv->pin_groups = groups; 758f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv->nr_groups = grp_cnt; 759f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv->pmx_functions = functions; 760f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv->nr_functions = func_idx; 761f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 762f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 763f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 764f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* register the pinctrl interface with the pinctrl subsystem */ 765312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_pinctrl_register(struct platform_device *pdev, 766f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv) 767f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 768f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct device *dev = &pdev->dev; 769f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct pinctrl_desc *ctrldesc; 770f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct pinctrl_dev *pctl_dev; 771f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct pinctrl_pin_desc *pindesc, *pdesc; 772f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct pinctrl_gpio_range grange; 773f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham char *pin_names; 774f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham int pin, ret; 775f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 776f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ctrldesc = devm_kzalloc(dev, sizeof(*ctrldesc), GFP_KERNEL); 777f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!ctrldesc) { 778f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "could not allocate memory for pinctrl desc\n"); 779f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 780f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 781f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 782f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ctrldesc->name = "exynos5440-pinctrl"; 783f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ctrldesc->owner = THIS_MODULE; 784f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ctrldesc->pctlops = &exynos5440_pctrl_ops; 785f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ctrldesc->pmxops = &exynos5440_pinmux_ops; 786f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ctrldesc->confops = &exynos5440_pinconf_ops; 787f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 788f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * 789f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham EXYNOS5440_MAX_PINS, GFP_KERNEL); 790f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!pindesc) { 791f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); 792f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 793f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 794f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ctrldesc->pins = pindesc; 795f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ctrldesc->npins = EXYNOS5440_MAX_PINS; 796f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 797f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* dynamically populate the pin number and pin name for pindesc */ 798f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++) 799f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pdesc->number = pin; 800f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 801f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* 802f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * allocate space for storing the dynamically generated names for all 803f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham * the pins which belong to this pin-controller. 804f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham */ 805f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * 806f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ctrldesc->npins, GFP_KERNEL); 807f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!pin_names) { 808f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(&pdev->dev, "mem alloc for pin names failed\n"); 809f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 810f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 811f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 812f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham /* for each pin, set the name of the pin */ 813f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham for (pin = 0; pin < ctrldesc->npins; pin++) { 81479bae27ff9e9d20196bec723e50f504cf5ef18adThomas Abraham snprintf(pin_names, 6, "gpio%02d", pin); 815f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pdesc = pindesc + pin; 816f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pdesc->name = pin_names; 817f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pin_names += PIN_NAME_LENGTH; 818f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 819f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 820f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ret = exynos5440_pinctrl_parse_dt(pdev, priv); 821f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (ret) 822f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return ret; 823f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 824f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, priv); 825f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!pctl_dev) { 826f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(&pdev->dev, "could not register pinctrl driver\n"); 827f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -EINVAL; 828f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 829f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 830f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grange.name = "exynos5440-pctrl-gpio-range"; 831f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grange.id = 0; 832f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grange.base = 0; 833f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grange.npins = EXYNOS5440_MAX_PINS; 834f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham grange.gc = priv->gc; 835f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham pinctrl_add_gpio_range(pctl_dev, &grange); 836f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 837f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 838f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 839f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* register the gpiolib interface with the gpiolib subsystem */ 840312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_gpiolib_register(struct platform_device *pdev, 841f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv) 842f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 843f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct gpio_chip *gc; 844f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham int ret; 845f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 846f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); 847f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!gc) { 848f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); 849f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 850f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 851f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 852f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham priv->gc = gc; 853f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc->base = 0; 854f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc->ngpio = EXYNOS5440_MAX_PINS; 855f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc->dev = &pdev->dev; 856f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc->set = exynos5440_gpio_set; 857f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc->get = exynos5440_gpio_get; 858f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc->direction_input = exynos5440_gpio_direction_input; 859f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc->direction_output = exynos5440_gpio_direction_output; 8608dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham gc->to_irq = exynos5440_gpio_to_irq; 861f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc->label = "gpiolib-exynos5440"; 862f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham gc->owner = THIS_MODULE; 863f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ret = gpiochip_add(gc); 864f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (ret) { 865f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(&pdev->dev, "failed to register gpio_chip %s, error " 866f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham "code: %d\n", gc->label, ret); 867f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return ret; 868f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 869f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 870f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 871f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 872f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 873f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham/* unregister the gpiolib interface with the gpiolib subsystem */ 874312b00e510af60175b2935404a1927e6480e91e7Arnd Bergmannstatic int exynos5440_gpiolib_unregister(struct platform_device *pdev, 875f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv) 876f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 8772fcea6cecbc965b4e02a39537d9d939f5251bbbdLinus Walleij gpiochip_remove(priv->gc); 878f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 879f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 880f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 8818dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic void exynos5440_gpio_irq_unmask(struct irq_data *irqd) 8828dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{ 8838dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct exynos5440_pinctrl_priv_data *d; 8848dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham unsigned long gpio_int; 8858dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 8868dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham d = irq_data_get_irq_chip_data(irqd); 8878dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham gpio_int = readl(d->reg_base + GPIO_INT); 8888dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham gpio_int |= 1 << irqd->hwirq; 8898dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham writel(gpio_int, d->reg_base + GPIO_INT); 8908dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham} 8918dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 8928dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic void exynos5440_gpio_irq_mask(struct irq_data *irqd) 8938dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{ 8948dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct exynos5440_pinctrl_priv_data *d; 8958dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham unsigned long gpio_int; 8968dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 8978dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham d = irq_data_get_irq_chip_data(irqd); 8988dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham gpio_int = readl(d->reg_base + GPIO_INT); 8998dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham gpio_int &= ~(1 << irqd->hwirq); 9008dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham writel(gpio_int, d->reg_base + GPIO_INT); 9018dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham} 9028dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9038dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* irq_chip for gpio interrupts */ 9048dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic struct irq_chip exynos5440_gpio_irq_chip = { 9058dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham .name = "exynos5440_gpio_irq_chip", 9068dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham .irq_unmask = exynos5440_gpio_irq_unmask, 9078dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham .irq_mask = exynos5440_gpio_irq_mask, 9088dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham}; 9098dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9108dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* interrupt handler for GPIO interrupts 0..7 */ 9118dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic irqreturn_t exynos5440_gpio_irq(int irq, void *data) 9128dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{ 9138dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct exynos5440_gpio_intr_data *intd = data; 9148dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct exynos5440_pinctrl_priv_data *d = intd->priv; 9158dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham int virq; 9168dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9178dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham virq = irq_linear_revmap(d->irq_domain, intd->gpio_int); 9188dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham if (!virq) 9198dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return IRQ_NONE; 9208dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham generic_handle_irq(virq); 9218dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return IRQ_HANDLED; 9228dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham} 9238dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9248dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic int exynos5440_gpio_irq_map(struct irq_domain *h, unsigned int virq, 9258dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham irq_hw_number_t hw) 9268dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{ 9278dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct exynos5440_pinctrl_priv_data *d = h->host_data; 9288dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9298dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham irq_set_chip_data(virq, d); 9308dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham irq_set_chip_and_handler(virq, &exynos5440_gpio_irq_chip, 9318dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham handle_level_irq); 9328dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham set_irq_flags(virq, IRQF_VALID); 9338dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return 0; 9348dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham} 9358dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9368dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* irq domain callbacks for gpio interrupt controller */ 9378dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic const struct irq_domain_ops exynos5440_gpio_irqd_ops = { 9388dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham .map = exynos5440_gpio_irq_map, 9398dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham .xlate = irq_domain_xlate_twocell, 9408dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham}; 9418dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9428dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham/* setup handling of gpio interrupts */ 9438dc3568d5527bfdb61afadea9284814a705b64ffThomas Abrahamstatic int exynos5440_gpio_irq_init(struct platform_device *pdev, 9448dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct exynos5440_pinctrl_priv_data *priv) 9458dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham{ 9468dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct device *dev = &pdev->dev; 9478dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham struct exynos5440_gpio_intr_data *intd; 9488dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham int i, irq, ret; 9498dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9508dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham intd = devm_kzalloc(dev, sizeof(*intd) * EXYNOS5440_MAX_GPIO_INT, 9518dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham GFP_KERNEL); 9528dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham if (!intd) { 9538dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham dev_err(dev, "failed to allocate memory for gpio intr data\n"); 9548dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return -ENOMEM; 9558dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham } 9568dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9578dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham for (i = 0; i < EXYNOS5440_MAX_GPIO_INT; i++) { 9588dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham irq = irq_of_parse_and_map(dev->of_node, i); 9598dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham if (irq <= 0) { 9608dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham dev_err(dev, "irq parsing failed\n"); 9618dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return -EINVAL; 9628dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham } 9638dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9648dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham intd->gpio_int = i; 9658dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham intd->priv = priv; 9668dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham ret = devm_request_irq(dev, irq, exynos5440_gpio_irq, 9678dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 0, dev_name(dev), intd++); 9688dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham if (ret) { 9698dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham dev_err(dev, "irq request failed\n"); 9708dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return -ENXIO; 9718dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham } 9728dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham } 9738dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9748dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham priv->irq_domain = irq_domain_add_linear(dev->of_node, 9758dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham EXYNOS5440_MAX_GPIO_INT, 9768dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham &exynos5440_gpio_irqd_ops, priv); 9778dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham if (!priv->irq_domain) { 9788dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham dev_err(dev, "failed to create irq domain\n"); 9798dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return -ENXIO; 9808dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham } 9818dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 9828dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return 0; 9838dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham} 9848dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 985150632b09aadf1996f5cb6c0c2620d63a01fe2deGreg Kroah-Hartmanstatic int exynos5440_pinctrl_probe(struct platform_device *pdev) 986f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 987f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct device *dev = &pdev->dev; 988f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct exynos5440_pinctrl_priv_data *priv; 989f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham struct resource *res; 990f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham int ret; 991f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 992f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!dev->of_node) { 993f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "device tree node not found\n"); 994f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENODEV; 995f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 996f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 997c078d78aa96ceafab7379b6a50e92d9d8e2f97b5Wei Yongjun priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 998f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (!priv) { 999f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_err(dev, "could not allocate memory for private data\n"); 1000f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return -ENOMEM; 1001f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 1002f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1003f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10049e0c1fb29a7c257a31c321c2437617b6b4d66168Thierry Reding priv->reg_base = devm_ioremap_resource(&pdev->dev, res); 10059e0c1fb29a7c257a31c321c2437617b6b4d66168Thierry Reding if (IS_ERR(priv->reg_base)) 10069e0c1fb29a7c257a31c321c2437617b6b4d66168Thierry Reding return PTR_ERR(priv->reg_base); 1007f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1008f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ret = exynos5440_gpiolib_register(pdev, priv); 1009f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (ret) 1010f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return ret; 1011f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1012f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham ret = exynos5440_pinctrl_register(pdev, priv); 1013f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham if (ret) { 1014f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham exynos5440_gpiolib_unregister(pdev, priv); 1015f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return ret; 10168dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham } 10178dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham 10188dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham ret = exynos5440_gpio_irq_init(pdev, priv); 10198dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham if (ret) { 10208dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham dev_err(dev, "failed to setup gpio interrupts\n"); 10218dc3568d5527bfdb61afadea9284814a705b64ffThomas Abraham return ret; 1022f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham } 1023f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1024f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham platform_set_drvdata(pdev, priv); 1025f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham dev_info(dev, "EXYNOS5440 pinctrl driver registered\n"); 1026f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return 0; 1027f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 1028f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1029f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic const struct of_device_id exynos5440_pinctrl_dt_match[] = { 1030f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham { .compatible = "samsung,exynos5440-pinctrl" }, 1031f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham {}, 1032f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 1033f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas AbrahamMODULE_DEVICE_TABLE(of, exynos5440_pinctrl_dt_match); 1034f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1035f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic struct platform_driver exynos5440_pinctrl_driver = { 1036f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .probe = exynos5440_pinctrl_probe, 1037f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .driver = { 1038f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .name = "exynos5440-pinctrl", 1039f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham .owner = THIS_MODULE, 1040606fca94f7bd156d37be1b38b3aded3ede5994b1Sachin Kamat .of_match_table = exynos5440_pinctrl_dt_match, 1041f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham }, 1042f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham}; 1043f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1044f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic int __init exynos5440_pinctrl_drv_register(void) 1045f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 1046f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham return platform_driver_register(&exynos5440_pinctrl_driver); 1047f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 1048f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahampostcore_initcall(exynos5440_pinctrl_drv_register); 1049f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1050f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahamstatic void __exit exynos5440_pinctrl_drv_unregister(void) 1051f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham{ 1052f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham platform_driver_unregister(&exynos5440_pinctrl_driver); 1053f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham} 1054f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abrahammodule_exit(exynos5440_pinctrl_drv_unregister); 1055f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas Abraham 1056f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas AbrahamMODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>"); 1057f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas AbrahamMODULE_DESCRIPTION("Samsung EXYNOS5440 SoC pinctrl driver"); 1058f0b9a7e521fa2fc5f3e0e57472126a6fed9cbb99Thomas AbrahamMODULE_LICENSE("GPL v2"); 1059