123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- /* Copyright (c) 2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/bitmap.h>
- #include <linux/bitops.h>
- #include <linux/delay.h>
- #include <linux/gpio.h>
- #include <linux/init.h>
- #include <linux/io.h>
- #include <linux/irq.h>
- #include <mach/msm_iomap.h>
- #include <mach/gpiomux.h>
- #include "gpio-msm-common.h"
- /* Bits of interest in the GPIO_IN_OUT register.
- */
- enum {
- GPIO_IN_BIT = 0,
- GPIO_OUT_BIT = 1
- };
- /* Bits of interest in the GPIO_INTR_STATUS register.
- */
- enum {
- INTR_STATUS_BIT = 0,
- };
- /* Bits of interest in the GPIO_CFG register.
- */
- enum {
- GPIO_OE_BIT = 9,
- };
- /* Bits of interest in the GPIO_INTR_CFG register.
- */
- enum {
- INTR_ENABLE_BIT = 0,
- INTR_POL_CTL_BIT = 1,
- INTR_DECT_CTL_BIT = 2,
- INTR_RAW_STATUS_EN_BIT = 4,
- INTR_TARGET_PROC_BIT = 5,
- INTR_DIR_CONN_EN_BIT = 8,
- };
- /*
- * There is no 'DC_POLARITY_LO' because the GIC is incapable
- * of asserting on falling edge or level-low conditions. Even though
- * the registers allow for low-polarity inputs, the case can never arise.
- */
- enum {
- DC_GPIO_SEL_BIT = 0,
- DC_POLARITY_BIT = 8,
- };
- /*
- * When a GPIO triggers, two separate decisions are made, controlled
- * by two separate flags.
- *
- * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS
- * register for that GPIO will be updated to reflect the triggering of that
- * gpio. If this bit is 0, this register will not be updated.
- * - Second, INTR_ENABLE controls whether an interrupt is triggered.
- *
- * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt
- * can be triggered but the status register will not reflect it.
- */
- #define INTR_RAW_STATUS_EN BIT(INTR_RAW_STATUS_EN_BIT)
- #define INTR_ENABLE BIT(INTR_ENABLE_BIT)
- #define INTR_POL_CTL_HI BIT(INTR_POL_CTL_BIT)
- #define INTR_DIR_CONN_EN BIT(INTR_DIR_CONN_EN_BIT)
- #define DC_POLARITY_HI BIT(DC_POLARITY_BIT)
- #define INTR_TARGET_PROC_APPS (4 << INTR_TARGET_PROC_BIT)
- #define INTR_TARGET_PROC_NONE (7 << INTR_TARGET_PROC_BIT)
- #define INTR_DECT_CTL_LEVEL (0 << INTR_DECT_CTL_BIT)
- #define INTR_DECT_CTL_POS_EDGE (1 << INTR_DECT_CTL_BIT)
- #define INTR_DECT_CTL_NEG_EDGE (2 << INTR_DECT_CTL_BIT)
- #define INTR_DECT_CTL_DUAL_EDGE (3 << INTR_DECT_CTL_BIT)
- #define INTR_DECT_CTL_MASK (3 << INTR_DECT_CTL_BIT)
- #define GPIO_CONFIG(gpio) (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
- #define GPIO_IN_OUT(gpio) (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
- #define GPIO_INTR_CFG(gpio) (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
- #define GPIO_INTR_STATUS(gpio) (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
- #define GPIO_DIR_CONN_INTR(intr) (MSM_TLMM_BASE + 0x2800 + (0x04 * (intr)))
- static inline void set_gpio_bits(unsigned n, void __iomem *reg)
- {
- __raw_writel(__raw_readl(reg) | n, reg);
- }
- static inline void clr_gpio_bits(unsigned n, void __iomem *reg)
- {
- __raw_writel(__raw_readl(reg) & ~n, reg);
- }
- unsigned __msm_gpio_get_inout(unsigned gpio)
- {
- return __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
- }
- void __msm_gpio_set_inout(unsigned gpio, unsigned val)
- {
- __raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(gpio));
- }
- void __msm_gpio_set_config_direction(unsigned gpio, int input, int val)
- {
- if (input) {
- clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
- } else {
- __msm_gpio_set_inout(gpio, val);
- set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
- }
- }
- static inline void set_gpio_bits_no_log(unsigned n, void __iomem *reg)
- {
- __raw_writel_no_log(__raw_readl_no_log(reg) | n, reg);
- }
- static inline void clr_gpio_bits_no_log(unsigned n, void __iomem *reg)
- {
- __raw_writel_no_log(__raw_readl_no_log(reg) & ~n, reg);
- }
- unsigned __msm_gpio_get_inout_no_log(unsigned gpio)
- {
- return __raw_readl_no_log(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
- }
- void __msm_gpio_set_inout_no_log(unsigned gpio, unsigned val)
- {
- __raw_writel_no_log(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(gpio));
- }
- void __msm_gpio_set_config_direction_no_log(unsigned gpio, int input, int val)
- {
- if (input) {
- clr_gpio_bits_no_log(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
- } else {
- __msm_gpio_set_inout_no_log(gpio, val);
- set_gpio_bits_no_log(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
- }
- }
- void __msm_gpio_set_polarity(unsigned gpio, unsigned val)
- {
- if (val)
- clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
- else
- set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
- }
- unsigned __msm_gpio_get_intr_status(unsigned gpio)
- {
- return __raw_readl(GPIO_INTR_STATUS(gpio)) &
- BIT(INTR_STATUS_BIT);
- }
- void __msm_gpio_set_intr_status(unsigned gpio)
- {
- __raw_writel(0, GPIO_INTR_STATUS(gpio));
- }
- unsigned __msm_gpio_get_intr_config(unsigned gpio)
- {
- return __raw_readl(GPIO_INTR_CFG(gpio));
- }
- void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val)
- {
- unsigned cfg;
- cfg = __raw_readl(GPIO_INTR_CFG(gpio));
- if (val) {
- cfg &= ~INTR_DIR_CONN_EN;
- cfg |= INTR_ENABLE;
- } else {
- cfg &= ~INTR_ENABLE;
- }
- __raw_writel(cfg, GPIO_INTR_CFG(gpio));
- }
- unsigned __msm_gpio_get_intr_cfg_enable(unsigned gpio)
- {
- return __msm_gpio_get_intr_config(gpio) & INTR_ENABLE;
- }
- void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type)
- {
- unsigned cfg;
- /* RAW_STATUS_EN is left on for all gpio irqs. Due to the
- * internal circuitry of TLMM, toggling the RAW_STATUS
- * could cause the INTR_STATUS to be set for EDGE interrupts.
- */
- cfg = INTR_RAW_STATUS_EN | INTR_TARGET_PROC_APPS;
- __raw_writel(cfg, GPIO_INTR_CFG(gpio));
- cfg &= ~INTR_DECT_CTL_MASK;
- if (type == IRQ_TYPE_EDGE_RISING)
- cfg |= INTR_DECT_CTL_POS_EDGE;
- else if (type == IRQ_TYPE_EDGE_FALLING)
- cfg |= INTR_DECT_CTL_NEG_EDGE;
- else if (type == IRQ_TYPE_EDGE_BOTH)
- cfg |= INTR_DECT_CTL_DUAL_EDGE;
- else
- cfg |= INTR_DECT_CTL_LEVEL;
- if (type & IRQ_TYPE_LEVEL_LOW)
- cfg &= ~INTR_POL_CTL_HI;
- else
- cfg |= INTR_POL_CTL_HI;
- __raw_writel(cfg, GPIO_INTR_CFG(gpio));
- /* Sometimes it might take a little while to update
- * the interrupt status after the RAW_STATUS is enabled
- * We clear the interrupt status before enabling the
- * interrupt in the unmask call-back.
- */
- udelay(5);
- }
- void __gpio_tlmm_config(unsigned config)
- {
- unsigned flags;
- unsigned gpio = GPIO_PIN(config);
- flags = ((GPIO_DIR(config) << 9) & (0x1 << 9)) |
- ((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
- ((GPIO_FUNC(config) << 2) & (0xf << 2)) |
- ((GPIO_PULL(config) & 0x3));
- __raw_writel(flags, GPIO_CONFIG(gpio));
- }
- void __msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
- unsigned int input_polarity)
- {
- unsigned cfg;
- set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
- cfg = __raw_readl(GPIO_INTR_CFG(gpio));
- cfg &= ~(INTR_TARGET_PROC_NONE | INTR_RAW_STATUS_EN | INTR_ENABLE);
- cfg |= INTR_TARGET_PROC_APPS | INTR_DIR_CONN_EN;
- __raw_writel(cfg, GPIO_INTR_CFG(gpio));
- cfg = gpio;
- if (input_polarity)
- cfg |= DC_POLARITY_HI;
- __raw_writel(cfg, GPIO_DIR_CONN_INTR(irq));
- }
|