162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. 462306a36Sopenharmony_ci// http://www.samsung.com/ 562306a36Sopenharmony_ci// 662306a36Sopenharmony_ci// Copyright 2008 Openmoko, Inc. 762306a36Sopenharmony_ci// Copyright 2008 Simtec Electronics 862306a36Sopenharmony_ci// Ben Dooks <ben@simtec.co.uk> 962306a36Sopenharmony_ci// http://armlinux.simtec.co.uk/ 1062306a36Sopenharmony_ci// 1162306a36Sopenharmony_ci// Samsung - GPIOlib support 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/irq.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/gpio.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/spinlock.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include <linux/device.h> 2262306a36Sopenharmony_ci#include <linux/ioport.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/of_address.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <asm/irq.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "irqs.h" 3062306a36Sopenharmony_ci#include "map.h" 3162306a36Sopenharmony_ci#include "regs-gpio.h" 3262306a36Sopenharmony_ci#include "gpio-samsung.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "cpu.h" 3562306a36Sopenharmony_ci#include "gpio-core.h" 3662306a36Sopenharmony_ci#include "gpio-cfg.h" 3762306a36Sopenharmony_ci#include "gpio-cfg-helpers.h" 3862306a36Sopenharmony_ci#include "pm.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, 4162306a36Sopenharmony_ci unsigned int off, samsung_gpio_pull_t pull) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci void __iomem *reg = chip->base + 0x08; 4462306a36Sopenharmony_ci int shift = off * 2; 4562306a36Sopenharmony_ci u32 pup; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci pup = __raw_readl(reg); 4862306a36Sopenharmony_ci pup &= ~(3 << shift); 4962306a36Sopenharmony_ci pup |= pull << shift; 5062306a36Sopenharmony_ci __raw_writel(pup, reg); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci return 0; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic samsung_gpio_pull_t samsung_gpio_getpull_updown(struct samsung_gpio_chip *chip, 5662306a36Sopenharmony_ci unsigned int off) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci void __iomem *reg = chip->base + 0x08; 5962306a36Sopenharmony_ci int shift = off * 2; 6062306a36Sopenharmony_ci u32 pup = __raw_readl(reg); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci pup >>= shift; 6362306a36Sopenharmony_ci pup &= 0x3; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci return (__force samsung_gpio_pull_t)pup; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int samsung_gpio_setcfg_2bit(struct samsung_gpio_chip *chip, 6962306a36Sopenharmony_ci unsigned int off, unsigned int cfg) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci void __iomem *reg = chip->base; 7262306a36Sopenharmony_ci unsigned int shift = off * 2; 7362306a36Sopenharmony_ci u32 con; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (samsung_gpio_is_cfg_special(cfg)) { 7662306a36Sopenharmony_ci cfg &= 0xf; 7762306a36Sopenharmony_ci if (cfg > 3) 7862306a36Sopenharmony_ci return -EINVAL; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci cfg <<= shift; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci con = __raw_readl(reg); 8462306a36Sopenharmony_ci con &= ~(0x3 << shift); 8562306a36Sopenharmony_ci con |= cfg; 8662306a36Sopenharmony_ci __raw_writel(con, reg); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * samsung_gpio_getcfg_2bit - Samsung 2bit style GPIO configuration read. 9362306a36Sopenharmony_ci * @chip: The gpio chip that is being configured. 9462306a36Sopenharmony_ci * @off: The offset for the GPIO being configured. 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * The reverse of samsung_gpio_setcfg_2bit(). Will return a value which 9762306a36Sopenharmony_ci * could be directly passed back to samsung_gpio_setcfg_2bit(), from the 9862306a36Sopenharmony_ci * S3C_GPIO_SPECIAL() macro. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic unsigned int samsung_gpio_getcfg_2bit(struct samsung_gpio_chip *chip, 10262306a36Sopenharmony_ci unsigned int off) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci u32 con; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci con = __raw_readl(chip->base); 10762306a36Sopenharmony_ci con >>= off * 2; 10862306a36Sopenharmony_ci con &= 3; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* this conversion works for IN and OUT as well as special mode */ 11162306a36Sopenharmony_ci return S3C_GPIO_SPECIAL(con); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* 11562306a36Sopenharmony_ci * samsung_gpio_setcfg_4bit - Samsung 4bit single register GPIO config. 11662306a36Sopenharmony_ci * @chip: The gpio chip that is being configured. 11762306a36Sopenharmony_ci * @off: The offset for the GPIO being configured. 11862306a36Sopenharmony_ci * @cfg: The configuration value to set. 11962306a36Sopenharmony_ci * 12062306a36Sopenharmony_ci * This helper deal with the GPIO cases where the control register has 4 bits 12162306a36Sopenharmony_ci * of control per GPIO, generally in the form of: 12262306a36Sopenharmony_ci * 0000 = Input 12362306a36Sopenharmony_ci * 0001 = Output 12462306a36Sopenharmony_ci * others = Special functions (dependent on bank) 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * Note, since the code to deal with the case where there are two control 12762306a36Sopenharmony_ci * registers instead of one, we do not have a separate set of functions for 12862306a36Sopenharmony_ci * each case. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int samsung_gpio_setcfg_4bit(struct samsung_gpio_chip *chip, 13262306a36Sopenharmony_ci unsigned int off, unsigned int cfg) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci void __iomem *reg = chip->base; 13562306a36Sopenharmony_ci unsigned int shift = (off & 7) * 4; 13662306a36Sopenharmony_ci u32 con; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (off < 8 && chip->chip.ngpio > 8) 13962306a36Sopenharmony_ci reg -= 4; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (samsung_gpio_is_cfg_special(cfg)) { 14262306a36Sopenharmony_ci cfg &= 0xf; 14362306a36Sopenharmony_ci cfg <<= shift; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci con = __raw_readl(reg); 14762306a36Sopenharmony_ci con &= ~(0xf << shift); 14862306a36Sopenharmony_ci con |= cfg; 14962306a36Sopenharmony_ci __raw_writel(con, reg); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * samsung_gpio_getcfg_4bit - Samsung 4bit single register GPIO config read. 15662306a36Sopenharmony_ci * @chip: The gpio chip that is being configured. 15762306a36Sopenharmony_ci * @off: The offset for the GPIO being configured. 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * The reverse of samsung_gpio_setcfg_4bit(), turning a gpio configuration 16062306a36Sopenharmony_ci * register setting into a value the software can use, such as could be passed 16162306a36Sopenharmony_ci * to samsung_gpio_setcfg_4bit(). 16262306a36Sopenharmony_ci * 16362306a36Sopenharmony_ci * @sa samsung_gpio_getcfg_2bit 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic unsigned samsung_gpio_getcfg_4bit(struct samsung_gpio_chip *chip, 16762306a36Sopenharmony_ci unsigned int off) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci void __iomem *reg = chip->base; 17062306a36Sopenharmony_ci unsigned int shift = (off & 7) * 4; 17162306a36Sopenharmony_ci u32 con; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (off < 8 && chip->chip.ngpio > 8) 17462306a36Sopenharmony_ci reg -= 4; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci con = __raw_readl(reg); 17762306a36Sopenharmony_ci con >>= shift; 17862306a36Sopenharmony_ci con &= 0xf; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* this conversion works for IN and OUT as well as special mode */ 18162306a36Sopenharmony_ci return S3C_GPIO_SPECIAL(con); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic void __init samsung_gpiolib_set_cfg(struct samsung_gpio_cfg *chipcfg, 18562306a36Sopenharmony_ci int nr_chips) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci for (; nr_chips > 0; nr_chips--, chipcfg++) { 18862306a36Sopenharmony_ci if (!chipcfg->set_config) 18962306a36Sopenharmony_ci chipcfg->set_config = samsung_gpio_setcfg_4bit; 19062306a36Sopenharmony_ci if (!chipcfg->get_config) 19162306a36Sopenharmony_ci chipcfg->get_config = samsung_gpio_getcfg_4bit; 19262306a36Sopenharmony_ci if (!chipcfg->set_pull) 19362306a36Sopenharmony_ci chipcfg->set_pull = samsung_gpio_setpull_updown; 19462306a36Sopenharmony_ci if (!chipcfg->get_pull) 19562306a36Sopenharmony_ci chipcfg->get_pull = samsung_gpio_getpull_updown; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic struct samsung_gpio_cfg samsung_gpio_cfgs[] = { 20062306a36Sopenharmony_ci [0] = { 20162306a36Sopenharmony_ci .cfg_eint = 0x0, 20262306a36Sopenharmony_ci }, 20362306a36Sopenharmony_ci [1] = { 20462306a36Sopenharmony_ci .cfg_eint = 0x3, 20562306a36Sopenharmony_ci }, 20662306a36Sopenharmony_ci [2] = { 20762306a36Sopenharmony_ci .cfg_eint = 0x7, 20862306a36Sopenharmony_ci }, 20962306a36Sopenharmony_ci [3] = { 21062306a36Sopenharmony_ci .cfg_eint = 0xF, 21162306a36Sopenharmony_ci }, 21262306a36Sopenharmony_ci [4] = { 21362306a36Sopenharmony_ci .cfg_eint = 0x0, 21462306a36Sopenharmony_ci .set_config = samsung_gpio_setcfg_2bit, 21562306a36Sopenharmony_ci .get_config = samsung_gpio_getcfg_2bit, 21662306a36Sopenharmony_ci }, 21762306a36Sopenharmony_ci [5] = { 21862306a36Sopenharmony_ci .cfg_eint = 0x2, 21962306a36Sopenharmony_ci .set_config = samsung_gpio_setcfg_2bit, 22062306a36Sopenharmony_ci .get_config = samsung_gpio_getcfg_2bit, 22162306a36Sopenharmony_ci }, 22262306a36Sopenharmony_ci [6] = { 22362306a36Sopenharmony_ci .cfg_eint = 0x3, 22462306a36Sopenharmony_ci .set_config = samsung_gpio_setcfg_2bit, 22562306a36Sopenharmony_ci .get_config = samsung_gpio_getcfg_2bit, 22662306a36Sopenharmony_ci }, 22762306a36Sopenharmony_ci [7] = { 22862306a36Sopenharmony_ci .set_config = samsung_gpio_setcfg_2bit, 22962306a36Sopenharmony_ci .get_config = samsung_gpio_getcfg_2bit, 23062306a36Sopenharmony_ci }, 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* 23462306a36Sopenharmony_ci * Default routines for controlling GPIO, based on the original S3C24XX 23562306a36Sopenharmony_ci * GPIO functions which deal with the case where each gpio bank of the 23662306a36Sopenharmony_ci * chip is as following: 23762306a36Sopenharmony_ci * 23862306a36Sopenharmony_ci * base + 0x00: Control register, 2 bits per gpio 23962306a36Sopenharmony_ci * gpio n: 2 bits starting at (2*n) 24062306a36Sopenharmony_ci * 00 = input, 01 = output, others mean special-function 24162306a36Sopenharmony_ci * base + 0x04: Data register, 1 bit per gpio 24262306a36Sopenharmony_ci * bit n: data bit n 24362306a36Sopenharmony_ci*/ 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int samsung_gpiolib_2bit_input(struct gpio_chip *chip, unsigned offset) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); 24862306a36Sopenharmony_ci void __iomem *base = ourchip->base; 24962306a36Sopenharmony_ci unsigned long flags; 25062306a36Sopenharmony_ci unsigned long con; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci samsung_gpio_lock(ourchip, flags); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci con = __raw_readl(base + 0x00); 25562306a36Sopenharmony_ci con &= ~(3 << (offset * 2)); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci __raw_writel(con, base + 0x00); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci samsung_gpio_unlock(ourchip, flags); 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int samsung_gpiolib_2bit_output(struct gpio_chip *chip, 26462306a36Sopenharmony_ci unsigned offset, int value) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); 26762306a36Sopenharmony_ci void __iomem *base = ourchip->base; 26862306a36Sopenharmony_ci unsigned long flags; 26962306a36Sopenharmony_ci unsigned long dat; 27062306a36Sopenharmony_ci unsigned long con; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci samsung_gpio_lock(ourchip, flags); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci dat = __raw_readl(base + 0x04); 27562306a36Sopenharmony_ci dat &= ~(1 << offset); 27662306a36Sopenharmony_ci if (value) 27762306a36Sopenharmony_ci dat |= 1 << offset; 27862306a36Sopenharmony_ci __raw_writel(dat, base + 0x04); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci con = __raw_readl(base + 0x00); 28162306a36Sopenharmony_ci con &= ~(3 << (offset * 2)); 28262306a36Sopenharmony_ci con |= 1 << (offset * 2); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci __raw_writel(con, base + 0x00); 28562306a36Sopenharmony_ci __raw_writel(dat, base + 0x04); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci samsung_gpio_unlock(ourchip, flags); 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci/* 29262306a36Sopenharmony_ci * The samsung_gpiolib_4bit routines are to control the gpio banks where 29362306a36Sopenharmony_ci * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the 29462306a36Sopenharmony_ci * following example: 29562306a36Sopenharmony_ci * 29662306a36Sopenharmony_ci * base + 0x00: Control register, 4 bits per gpio 29762306a36Sopenharmony_ci * gpio n: 4 bits starting at (4*n) 29862306a36Sopenharmony_ci * 0000 = input, 0001 = output, others mean special-function 29962306a36Sopenharmony_ci * base + 0x04: Data register, 1 bit per gpio 30062306a36Sopenharmony_ci * bit n: data bit n 30162306a36Sopenharmony_ci * 30262306a36Sopenharmony_ci * Note, since the data register is one bit per gpio and is at base + 0x4 30362306a36Sopenharmony_ci * we can use samsung_gpiolib_get and samsung_gpiolib_set to change the 30462306a36Sopenharmony_ci * state of the output. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int samsung_gpiolib_4bit_input(struct gpio_chip *chip, 30862306a36Sopenharmony_ci unsigned int offset) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); 31162306a36Sopenharmony_ci void __iomem *base = ourchip->base; 31262306a36Sopenharmony_ci unsigned long con; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci con = __raw_readl(base + GPIOCON_OFF); 31562306a36Sopenharmony_ci if (ourchip->bitmap_gpio_int & BIT(offset)) 31662306a36Sopenharmony_ci con |= 0xf << con_4bit_shift(offset); 31762306a36Sopenharmony_ci else 31862306a36Sopenharmony_ci con &= ~(0xf << con_4bit_shift(offset)); 31962306a36Sopenharmony_ci __raw_writel(con, base + GPIOCON_OFF); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci pr_debug("%s: %p: CON now %08lx\n", __func__, base, con); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int samsung_gpiolib_4bit_output(struct gpio_chip *chip, 32762306a36Sopenharmony_ci unsigned int offset, int value) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); 33062306a36Sopenharmony_ci void __iomem *base = ourchip->base; 33162306a36Sopenharmony_ci unsigned long con; 33262306a36Sopenharmony_ci unsigned long dat; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci con = __raw_readl(base + GPIOCON_OFF); 33562306a36Sopenharmony_ci con &= ~(0xf << con_4bit_shift(offset)); 33662306a36Sopenharmony_ci con |= 0x1 << con_4bit_shift(offset); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci dat = __raw_readl(base + GPIODAT_OFF); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (value) 34162306a36Sopenharmony_ci dat |= 1 << offset; 34262306a36Sopenharmony_ci else 34362306a36Sopenharmony_ci dat &= ~(1 << offset); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci __raw_writel(dat, base + GPIODAT_OFF); 34662306a36Sopenharmony_ci __raw_writel(con, base + GPIOCON_OFF); 34762306a36Sopenharmony_ci __raw_writel(dat, base + GPIODAT_OFF); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/* 35562306a36Sopenharmony_ci * The next set of routines are for the case where the GPIO configuration 35662306a36Sopenharmony_ci * registers are 4 bits per GPIO but there is more than one register (the 35762306a36Sopenharmony_ci * bank has more than 8 GPIOs. 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci * This case is the similar to the 4 bit case, but the registers are as 36062306a36Sopenharmony_ci * follows: 36162306a36Sopenharmony_ci * 36262306a36Sopenharmony_ci * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs) 36362306a36Sopenharmony_ci * gpio n: 4 bits starting at (4*n) 36462306a36Sopenharmony_ci * 0000 = input, 0001 = output, others mean special-function 36562306a36Sopenharmony_ci * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs) 36662306a36Sopenharmony_ci * gpio n: 4 bits starting at (4*n) 36762306a36Sopenharmony_ci * 0000 = input, 0001 = output, others mean special-function 36862306a36Sopenharmony_ci * base + 0x08: Data register, 1 bit per gpio 36962306a36Sopenharmony_ci * bit n: data bit n 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * To allow us to use the samsung_gpiolib_get and samsung_gpiolib_set 37262306a36Sopenharmony_ci * routines we store the 'base + 0x4' address so that these routines see 37362306a36Sopenharmony_ci * the data register at ourchip->base + 0x04. 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, 37762306a36Sopenharmony_ci unsigned int offset) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); 38062306a36Sopenharmony_ci void __iomem *base = ourchip->base; 38162306a36Sopenharmony_ci void __iomem *regcon = base; 38262306a36Sopenharmony_ci unsigned long con; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (offset > 7) 38562306a36Sopenharmony_ci offset -= 8; 38662306a36Sopenharmony_ci else 38762306a36Sopenharmony_ci regcon -= 4; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci con = __raw_readl(regcon); 39062306a36Sopenharmony_ci con &= ~(0xf << con_4bit_shift(offset)); 39162306a36Sopenharmony_ci __raw_writel(con, regcon); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci pr_debug("%s: %p: CON %08lx\n", __func__, base, con); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci return 0; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, 39962306a36Sopenharmony_ci unsigned int offset, int value) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); 40262306a36Sopenharmony_ci void __iomem *base = ourchip->base; 40362306a36Sopenharmony_ci void __iomem *regcon = base; 40462306a36Sopenharmony_ci unsigned long con; 40562306a36Sopenharmony_ci unsigned long dat; 40662306a36Sopenharmony_ci unsigned con_offset = offset; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (con_offset > 7) 40962306a36Sopenharmony_ci con_offset -= 8; 41062306a36Sopenharmony_ci else 41162306a36Sopenharmony_ci regcon -= 4; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci con = __raw_readl(regcon); 41462306a36Sopenharmony_ci con &= ~(0xf << con_4bit_shift(con_offset)); 41562306a36Sopenharmony_ci con |= 0x1 << con_4bit_shift(con_offset); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci dat = __raw_readl(base + GPIODAT_OFF); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (value) 42062306a36Sopenharmony_ci dat |= 1 << offset; 42162306a36Sopenharmony_ci else 42262306a36Sopenharmony_ci dat &= ~(1 << offset); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci __raw_writel(dat, base + GPIODAT_OFF); 42562306a36Sopenharmony_ci __raw_writel(con, regcon); 42662306a36Sopenharmony_ci __raw_writel(dat, base + GPIODAT_OFF); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return 0; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void samsung_gpiolib_set(struct gpio_chip *chip, 43462306a36Sopenharmony_ci unsigned offset, int value) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); 43762306a36Sopenharmony_ci void __iomem *base = ourchip->base; 43862306a36Sopenharmony_ci unsigned long flags; 43962306a36Sopenharmony_ci unsigned long dat; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci samsung_gpio_lock(ourchip, flags); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci dat = __raw_readl(base + 0x04); 44462306a36Sopenharmony_ci dat &= ~(1 << offset); 44562306a36Sopenharmony_ci if (value) 44662306a36Sopenharmony_ci dat |= 1 << offset; 44762306a36Sopenharmony_ci __raw_writel(dat, base + 0x04); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci samsung_gpio_unlock(ourchip, flags); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int samsung_gpiolib_get(struct gpio_chip *chip, unsigned offset) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); 45562306a36Sopenharmony_ci unsigned long val; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci val = __raw_readl(ourchip->base + 0x04); 45862306a36Sopenharmony_ci val >>= offset; 45962306a36Sopenharmony_ci val &= 1; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return val; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci/* 46562306a36Sopenharmony_ci * CONFIG_S3C_GPIO_TRACK enables the tracking of the s3c specific gpios 46662306a36Sopenharmony_ci * for use with the configuration calls, and other parts of the s3c gpiolib 46762306a36Sopenharmony_ci * support code. 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci * Not all s3c support code will need this, as some configurations of cpu 47062306a36Sopenharmony_ci * may only support one or two different configuration options and have an 47162306a36Sopenharmony_ci * easy gpio to samsung_gpio_chip mapping function. If this is the case, then 47262306a36Sopenharmony_ci * the machine support file should provide its own samsung_gpiolib_getchip() 47362306a36Sopenharmony_ci * and any other necessary functions. 47462306a36Sopenharmony_ci */ 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci#ifdef CONFIG_S3C_GPIO_TRACK 47762306a36Sopenharmony_cistruct samsung_gpio_chip *s3c_gpios[S3C_GPIO_END]; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic __init void s3c_gpiolib_track(struct samsung_gpio_chip *chip) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci unsigned int gpn; 48262306a36Sopenharmony_ci int i; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci gpn = chip->chip.base; 48562306a36Sopenharmony_ci for (i = 0; i < chip->chip.ngpio; i++, gpn++) { 48662306a36Sopenharmony_ci BUG_ON(gpn >= ARRAY_SIZE(s3c_gpios)); 48762306a36Sopenharmony_ci s3c_gpios[gpn] = chip; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci#endif /* CONFIG_S3C_GPIO_TRACK */ 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/* 49362306a36Sopenharmony_ci * samsung_gpiolib_add() - add the Samsung gpio_chip. 49462306a36Sopenharmony_ci * @chip: The chip to register 49562306a36Sopenharmony_ci * 49662306a36Sopenharmony_ci * This is a wrapper to gpiochip_add() that takes our specific gpio chip 49762306a36Sopenharmony_ci * information and makes the necessary alterations for the platform and 49862306a36Sopenharmony_ci * notes the information for use with the configuration systems and any 49962306a36Sopenharmony_ci * other parts of the system. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci struct gpio_chip *gc = &chip->chip; 50562306a36Sopenharmony_ci int ret; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci BUG_ON(!chip->base); 50862306a36Sopenharmony_ci BUG_ON(!gc->label); 50962306a36Sopenharmony_ci BUG_ON(!gc->ngpio); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci spin_lock_init(&chip->lock); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (!gc->direction_input) 51462306a36Sopenharmony_ci gc->direction_input = samsung_gpiolib_2bit_input; 51562306a36Sopenharmony_ci if (!gc->direction_output) 51662306a36Sopenharmony_ci gc->direction_output = samsung_gpiolib_2bit_output; 51762306a36Sopenharmony_ci if (!gc->set) 51862306a36Sopenharmony_ci gc->set = samsung_gpiolib_set; 51962306a36Sopenharmony_ci if (!gc->get) 52062306a36Sopenharmony_ci gc->get = samsung_gpiolib_get; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci#ifdef CONFIG_PM 52362306a36Sopenharmony_ci if (chip->pm != NULL) { 52462306a36Sopenharmony_ci if (!chip->pm->save || !chip->pm->resume) 52562306a36Sopenharmony_ci pr_err("gpio: %s has missing PM functions\n", 52662306a36Sopenharmony_ci gc->label); 52762306a36Sopenharmony_ci } else 52862306a36Sopenharmony_ci pr_err("gpio: %s has no PM function\n", gc->label); 52962306a36Sopenharmony_ci#endif 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* gpiochip_add() prints own failure message on error. */ 53262306a36Sopenharmony_ci ret = gpiochip_add_data(gc, chip); 53362306a36Sopenharmony_ci if (ret >= 0) 53462306a36Sopenharmony_ci s3c_gpiolib_track(chip); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic void __init samsung_gpiolib_add_2bit_chips(struct samsung_gpio_chip *chip, 53862306a36Sopenharmony_ci int nr_chips, void __iomem *base, 53962306a36Sopenharmony_ci unsigned int offset) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci int i; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci for (i = 0 ; i < nr_chips; i++, chip++) { 54462306a36Sopenharmony_ci chip->chip.direction_input = samsung_gpiolib_2bit_input; 54562306a36Sopenharmony_ci chip->chip.direction_output = samsung_gpiolib_2bit_output; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (!chip->config) 54862306a36Sopenharmony_ci chip->config = &samsung_gpio_cfgs[7]; 54962306a36Sopenharmony_ci if (!chip->pm) 55062306a36Sopenharmony_ci chip->pm = __gpio_pm(&samsung_gpio_pm_2bit); 55162306a36Sopenharmony_ci if ((base != NULL) && (chip->base == NULL)) 55262306a36Sopenharmony_ci chip->base = base + ((i) * offset); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci samsung_gpiolib_add(chip); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci/* 55962306a36Sopenharmony_ci * samsung_gpiolib_add_4bit_chips - 4bit single register GPIO config. 56062306a36Sopenharmony_ci * @chip: The gpio chip that is being configured. 56162306a36Sopenharmony_ci * @nr_chips: The no of chips (gpio ports) for the GPIO being configured. 56262306a36Sopenharmony_ci * 56362306a36Sopenharmony_ci * This helper deal with the GPIO cases where the control register has 4 bits 56462306a36Sopenharmony_ci * of control per GPIO, generally in the form of: 56562306a36Sopenharmony_ci * 0000 = Input 56662306a36Sopenharmony_ci * 0001 = Output 56762306a36Sopenharmony_ci * others = Special functions (dependent on bank) 56862306a36Sopenharmony_ci * 56962306a36Sopenharmony_ci * Note, since the code to deal with the case where there are two control 57062306a36Sopenharmony_ci * registers instead of one, we do not have a separate set of function 57162306a36Sopenharmony_ci * (samsung_gpiolib_add_4bit2_chips)for each case. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic void __init samsung_gpiolib_add_4bit_chips(struct samsung_gpio_chip *chip, 57562306a36Sopenharmony_ci int nr_chips, void __iomem *base) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci int i; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci for (i = 0 ; i < nr_chips; i++, chip++) { 58062306a36Sopenharmony_ci chip->chip.direction_input = samsung_gpiolib_4bit_input; 58162306a36Sopenharmony_ci chip->chip.direction_output = samsung_gpiolib_4bit_output; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (!chip->config) 58462306a36Sopenharmony_ci chip->config = &samsung_gpio_cfgs[2]; 58562306a36Sopenharmony_ci if (!chip->pm) 58662306a36Sopenharmony_ci chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); 58762306a36Sopenharmony_ci if ((base != NULL) && (chip->base == NULL)) 58862306a36Sopenharmony_ci chip->base = base + ((i) * 0x20); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci chip->bitmap_gpio_int = 0; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci samsung_gpiolib_add(chip); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_cistatic void __init samsung_gpiolib_add_4bit2_chips(struct samsung_gpio_chip *chip, 59762306a36Sopenharmony_ci int nr_chips) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci for (; nr_chips > 0; nr_chips--, chip++) { 60062306a36Sopenharmony_ci chip->chip.direction_input = samsung_gpiolib_4bit2_input; 60162306a36Sopenharmony_ci chip->chip.direction_output = samsung_gpiolib_4bit2_output; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (!chip->config) 60462306a36Sopenharmony_ci chip->config = &samsung_gpio_cfgs[2]; 60562306a36Sopenharmony_ci if (!chip->pm) 60662306a36Sopenharmony_ci chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci samsung_gpiolib_add(chip); 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ciint samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct samsung_gpio_chip *samsung_chip = gpiochip_get_data(chip); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return samsung_chip->irq_base + offset; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic int s3c64xx_gpiolib_mbank_to_irq(struct gpio_chip *chip, unsigned pin) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci return pin < 5 ? IRQ_EINT(23) + pin : -ENXIO; 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic int s3c64xx_gpiolib_lbank_to_irq(struct gpio_chip *chip, unsigned pin) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci/* 63062306a36Sopenharmony_ci * GPIO bank summary: 63162306a36Sopenharmony_ci * 63262306a36Sopenharmony_ci * Bank GPIOs Style SlpCon ExtInt Group 63362306a36Sopenharmony_ci * A 8 4Bit Yes 1 63462306a36Sopenharmony_ci * B 7 4Bit Yes 1 63562306a36Sopenharmony_ci * C 8 4Bit Yes 2 63662306a36Sopenharmony_ci * D 5 4Bit Yes 3 63762306a36Sopenharmony_ci * E 5 4Bit Yes None 63862306a36Sopenharmony_ci * F 16 2Bit Yes 4 [1] 63962306a36Sopenharmony_ci * G 7 4Bit Yes 5 64062306a36Sopenharmony_ci * H 10 4Bit[2] Yes 6 64162306a36Sopenharmony_ci * I 16 2Bit Yes None 64262306a36Sopenharmony_ci * J 12 2Bit Yes None 64362306a36Sopenharmony_ci * K 16 4Bit[2] No None 64462306a36Sopenharmony_ci * L 15 4Bit[2] No None 64562306a36Sopenharmony_ci * M 6 4Bit No IRQ_EINT 64662306a36Sopenharmony_ci * N 16 2Bit No IRQ_EINT 64762306a36Sopenharmony_ci * O 16 2Bit Yes 7 64862306a36Sopenharmony_ci * P 15 2Bit Yes 8 64962306a36Sopenharmony_ci * Q 9 2Bit Yes 9 65062306a36Sopenharmony_ci * 65162306a36Sopenharmony_ci * [1] BANKF pins 14,15 do not form part of the external interrupt sources 65262306a36Sopenharmony_ci * [2] BANK has two control registers, GPxCON0 and GPxCON1 65362306a36Sopenharmony_ci */ 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic struct samsung_gpio_chip s3c64xx_gpios_4bit[] = { 65662306a36Sopenharmony_ci { 65762306a36Sopenharmony_ci .chip = { 65862306a36Sopenharmony_ci .base = S3C64XX_GPA(0), 65962306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_A_NR, 66062306a36Sopenharmony_ci .label = "GPA", 66162306a36Sopenharmony_ci }, 66262306a36Sopenharmony_ci }, { 66362306a36Sopenharmony_ci .chip = { 66462306a36Sopenharmony_ci .base = S3C64XX_GPB(0), 66562306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_B_NR, 66662306a36Sopenharmony_ci .label = "GPB", 66762306a36Sopenharmony_ci }, 66862306a36Sopenharmony_ci }, { 66962306a36Sopenharmony_ci .chip = { 67062306a36Sopenharmony_ci .base = S3C64XX_GPC(0), 67162306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_C_NR, 67262306a36Sopenharmony_ci .label = "GPC", 67362306a36Sopenharmony_ci }, 67462306a36Sopenharmony_ci }, { 67562306a36Sopenharmony_ci .chip = { 67662306a36Sopenharmony_ci .base = S3C64XX_GPD(0), 67762306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_D_NR, 67862306a36Sopenharmony_ci .label = "GPD", 67962306a36Sopenharmony_ci }, 68062306a36Sopenharmony_ci }, { 68162306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[0], 68262306a36Sopenharmony_ci .chip = { 68362306a36Sopenharmony_ci .base = S3C64XX_GPE(0), 68462306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_E_NR, 68562306a36Sopenharmony_ci .label = "GPE", 68662306a36Sopenharmony_ci }, 68762306a36Sopenharmony_ci }, { 68862306a36Sopenharmony_ci .base = S3C64XX_GPG_BASE, 68962306a36Sopenharmony_ci .chip = { 69062306a36Sopenharmony_ci .base = S3C64XX_GPG(0), 69162306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_G_NR, 69262306a36Sopenharmony_ci .label = "GPG", 69362306a36Sopenharmony_ci }, 69462306a36Sopenharmony_ci }, { 69562306a36Sopenharmony_ci .base = S3C64XX_GPM_BASE, 69662306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[1], 69762306a36Sopenharmony_ci .chip = { 69862306a36Sopenharmony_ci .base = S3C64XX_GPM(0), 69962306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_M_NR, 70062306a36Sopenharmony_ci .label = "GPM", 70162306a36Sopenharmony_ci .to_irq = s3c64xx_gpiolib_mbank_to_irq, 70262306a36Sopenharmony_ci }, 70362306a36Sopenharmony_ci }, 70462306a36Sopenharmony_ci}; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic struct samsung_gpio_chip s3c64xx_gpios_4bit2[] = { 70762306a36Sopenharmony_ci { 70862306a36Sopenharmony_ci .base = S3C64XX_GPH_BASE + 0x4, 70962306a36Sopenharmony_ci .chip = { 71062306a36Sopenharmony_ci .base = S3C64XX_GPH(0), 71162306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_H_NR, 71262306a36Sopenharmony_ci .label = "GPH", 71362306a36Sopenharmony_ci }, 71462306a36Sopenharmony_ci }, { 71562306a36Sopenharmony_ci .base = S3C64XX_GPK_BASE + 0x4, 71662306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[0], 71762306a36Sopenharmony_ci .chip = { 71862306a36Sopenharmony_ci .base = S3C64XX_GPK(0), 71962306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_K_NR, 72062306a36Sopenharmony_ci .label = "GPK", 72162306a36Sopenharmony_ci }, 72262306a36Sopenharmony_ci }, { 72362306a36Sopenharmony_ci .base = S3C64XX_GPL_BASE + 0x4, 72462306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[1], 72562306a36Sopenharmony_ci .chip = { 72662306a36Sopenharmony_ci .base = S3C64XX_GPL(0), 72762306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_L_NR, 72862306a36Sopenharmony_ci .label = "GPL", 72962306a36Sopenharmony_ci .to_irq = s3c64xx_gpiolib_lbank_to_irq, 73062306a36Sopenharmony_ci }, 73162306a36Sopenharmony_ci }, 73262306a36Sopenharmony_ci}; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic struct samsung_gpio_chip s3c64xx_gpios_2bit[] = { 73562306a36Sopenharmony_ci { 73662306a36Sopenharmony_ci .base = S3C64XX_GPF_BASE, 73762306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[6], 73862306a36Sopenharmony_ci .chip = { 73962306a36Sopenharmony_ci .base = S3C64XX_GPF(0), 74062306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_F_NR, 74162306a36Sopenharmony_ci .label = "GPF", 74262306a36Sopenharmony_ci }, 74362306a36Sopenharmony_ci }, { 74462306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[7], 74562306a36Sopenharmony_ci .chip = { 74662306a36Sopenharmony_ci .base = S3C64XX_GPI(0), 74762306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_I_NR, 74862306a36Sopenharmony_ci .label = "GPI", 74962306a36Sopenharmony_ci }, 75062306a36Sopenharmony_ci }, { 75162306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[7], 75262306a36Sopenharmony_ci .chip = { 75362306a36Sopenharmony_ci .base = S3C64XX_GPJ(0), 75462306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_J_NR, 75562306a36Sopenharmony_ci .label = "GPJ", 75662306a36Sopenharmony_ci }, 75762306a36Sopenharmony_ci }, { 75862306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[6], 75962306a36Sopenharmony_ci .chip = { 76062306a36Sopenharmony_ci .base = S3C64XX_GPO(0), 76162306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_O_NR, 76262306a36Sopenharmony_ci .label = "GPO", 76362306a36Sopenharmony_ci }, 76462306a36Sopenharmony_ci }, { 76562306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[6], 76662306a36Sopenharmony_ci .chip = { 76762306a36Sopenharmony_ci .base = S3C64XX_GPP(0), 76862306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_P_NR, 76962306a36Sopenharmony_ci .label = "GPP", 77062306a36Sopenharmony_ci }, 77162306a36Sopenharmony_ci }, { 77262306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[6], 77362306a36Sopenharmony_ci .chip = { 77462306a36Sopenharmony_ci .base = S3C64XX_GPQ(0), 77562306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_Q_NR, 77662306a36Sopenharmony_ci .label = "GPQ", 77762306a36Sopenharmony_ci }, 77862306a36Sopenharmony_ci }, { 77962306a36Sopenharmony_ci .base = S3C64XX_GPN_BASE, 78062306a36Sopenharmony_ci .irq_base = IRQ_EINT(0), 78162306a36Sopenharmony_ci .config = &samsung_gpio_cfgs[5], 78262306a36Sopenharmony_ci .chip = { 78362306a36Sopenharmony_ci .base = S3C64XX_GPN(0), 78462306a36Sopenharmony_ci .ngpio = S3C64XX_GPIO_N_NR, 78562306a36Sopenharmony_ci .label = "GPN", 78662306a36Sopenharmony_ci .to_irq = samsung_gpiolib_to_irq, 78762306a36Sopenharmony_ci }, 78862306a36Sopenharmony_ci }, 78962306a36Sopenharmony_ci}; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci/* TODO: cleanup soc_is_* */ 79262306a36Sopenharmony_cistatic __init int samsung_gpiolib_init(void) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci /* 79562306a36Sopenharmony_ci * Currently there are two drivers that can provide GPIO support for 79662306a36Sopenharmony_ci * Samsung SoCs. For device tree enabled platforms, the new 79762306a36Sopenharmony_ci * pinctrl-samsung driver is used, providing both GPIO and pin control 79862306a36Sopenharmony_ci * interfaces. For legacy (non-DT) platforms this driver is used. 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_ci if (of_have_populated_dt()) 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (soc_is_s3c64xx()) { 80462306a36Sopenharmony_ci samsung_gpiolib_set_cfg(samsung_gpio_cfgs, 80562306a36Sopenharmony_ci ARRAY_SIZE(samsung_gpio_cfgs)); 80662306a36Sopenharmony_ci samsung_gpiolib_add_2bit_chips(s3c64xx_gpios_2bit, 80762306a36Sopenharmony_ci ARRAY_SIZE(s3c64xx_gpios_2bit), 80862306a36Sopenharmony_ci S3C64XX_VA_GPIO + 0xE0, 0x20); 80962306a36Sopenharmony_ci samsung_gpiolib_add_4bit_chips(s3c64xx_gpios_4bit, 81062306a36Sopenharmony_ci ARRAY_SIZE(s3c64xx_gpios_4bit), 81162306a36Sopenharmony_ci S3C64XX_VA_GPIO); 81262306a36Sopenharmony_ci samsung_gpiolib_add_4bit2_chips(s3c64xx_gpios_4bit2, 81362306a36Sopenharmony_ci ARRAY_SIZE(s3c64xx_gpios_4bit2)); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci return 0; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_cicore_initcall(samsung_gpiolib_init); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ciint s3c_gpio_cfgpin(unsigned int pin, unsigned int config) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); 82362306a36Sopenharmony_ci unsigned long flags; 82462306a36Sopenharmony_ci int offset; 82562306a36Sopenharmony_ci int ret; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (!chip) 82862306a36Sopenharmony_ci return -EINVAL; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci offset = pin - chip->chip.base; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci samsung_gpio_lock(chip, flags); 83362306a36Sopenharmony_ci ret = samsung_gpio_do_setcfg(chip, offset, config); 83462306a36Sopenharmony_ci samsung_gpio_unlock(chip, flags); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci return ret; 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ciEXPORT_SYMBOL(s3c_gpio_cfgpin); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ciint s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, 84162306a36Sopenharmony_ci unsigned int cfg) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci int ret; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci for (; nr > 0; nr--, start++) { 84662306a36Sopenharmony_ci ret = s3c_gpio_cfgpin(start, cfg); 84762306a36Sopenharmony_ci if (ret != 0) 84862306a36Sopenharmony_ci return ret; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci return 0; 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(s3c_gpio_cfgpin_range); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ciint s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, 85662306a36Sopenharmony_ci unsigned int cfg, samsung_gpio_pull_t pull) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci int ret; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci for (; nr > 0; nr--, start++) { 86162306a36Sopenharmony_ci s3c_gpio_setpull(start, pull); 86262306a36Sopenharmony_ci ret = s3c_gpio_cfgpin(start, cfg); 86362306a36Sopenharmony_ci if (ret != 0) 86462306a36Sopenharmony_ci return ret; 86562306a36Sopenharmony_ci } 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci return 0; 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(s3c_gpio_cfgall_range); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ciint s3c_gpio_setpull(unsigned int pin, samsung_gpio_pull_t pull) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); 87462306a36Sopenharmony_ci unsigned long flags; 87562306a36Sopenharmony_ci int offset, ret; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (!chip) 87862306a36Sopenharmony_ci return -EINVAL; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci offset = pin - chip->chip.base; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci samsung_gpio_lock(chip, flags); 88362306a36Sopenharmony_ci ret = samsung_gpio_do_setpull(chip, offset, pull); 88462306a36Sopenharmony_ci samsung_gpio_unlock(chip, flags); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci return ret; 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ciEXPORT_SYMBOL(s3c_gpio_setpull); 889