#include <linux/i2c/twl4030-gpio.h>
+/*
+ * The GPIO "subchip" supports 18 GPIOs which can be configured as
+ * inputs or outputs, with pullups or pulldowns on each pin. Each
+ * GPIO can trigger interrupts on either or both edges.
+ *
+ * GPIO interrupts can be fed to either of two IRQ lines; this is
+ * intended to support multiple hosts.
+ *
+ * There are also two LED pins used sometimes as output-only GPIOs.
+ *
+ * FIXME code currently only handles the first IRQ line.
+ */
+
+
static inline void activate_irq(int irq)
{
#ifdef CONFIG_ARM
#define is_module() false
#endif
-/* BitField Definitions */
-
-/* Data banks : 3 banks for 8 gpios each */
-#define DATA_BANK_MAX 8
-#define GET_GPIO_DATA_BANK(x) ((x)/DATA_BANK_MAX)
-#define GET_GPIO_DATA_OFF(x) ((x)%DATA_BANK_MAX)
-
-/* GPIODATADIR Fields each block 0-7 */
-#define BIT_GPIODATADIR_GPIOxDIR(x) (x)
-#define MASK_GPIODATADIR_GPIOxDIR(x) (0x01 << (x))
-
-/* GPIODATAIN Fields each block 0-7 */
-#define BIT_GPIODATAIN_GPIOxIN(x) (x)
-#define MASK_GPIODATAIN_GPIOxIN(x) (0x01 << (x))
-
-/* GPIODATAOUT Fields each block 0-7 */
-#define BIT_GPIODATAOUT_GPIOxOUT(x) (x)
-#define MASK_GPIODATAOUT_GPIOxOUT(x) (0x01 << (x))
-
-/* CLEARGPIODATAOUT Fields */
-#define BIT_CLEARGPIODATAOUT_GPIOxOUT(x) (x)
-#define MASK_CLEARGPIODATAOUT_GPIOxOUT(x) (0x01 << (x))
-
-/* SETGPIODATAOUT Fields */
-#define BIT_SETGPIODATAOUT_GPIOxOUT(x) (x)
-#define MASK_SETGPIODATAOUT_GPIOxOUT(x) (0x01 << (x))
-
-/* GPIO_DEBEN Fields */
-#define BIT_GPIO_DEBEN_GPIOxDEB(x) (x)
-#define MASK_GPIO_DEBEN_GPIOxDEB(x) (0x01 << (x))
-
-/* GPIO_ISR1A Fields */
-#define BIT_GPIO_ISR_GPIOxISR(x) (x)
-#define MASK_GPIO_ISR_GPIOxISR(x) (0x01 << (x))
-
-/* GPIO_IMR1A Fields */
-#define BIT_GPIO_IMR1A_GPIOxIMR(x) (x)
-#define MASK_GPIO_IMR1A_GPIOxIMR(x) (0x01 << (x))
-
-/* GPIO_SIR1 Fields */
-#define BIT_GPIO_SIR1_GPIOxSIR(x) (x)
-#define MASK_GPIO_SIR1_GPIO0SIR (0x01 << (x))
-
-
-/* Control banks : 5 banks for 4 gpios each */
-#define DATA_CTL_MAX 4
-#define GET_GPIO_CTL_BANK(x) ((x)/DATA_CTL_MAX)
-#define GET_GPIO_CTL_OFF(x) ((x)%DATA_CTL_MAX)
-#define GPIO_BANK_MAX GET_GPIO_CTL_BANK(TWL4030_GPIO_MAX)
-
-/* GPIOPUPDCTRx Fields 5 banks of 4 gpios each */
-#define BIT_GPIOPUPDCTR1_GPIOxPD(x) (2 * (x))
-#define MASK_GPIOPUPDCTR1_GPIOxPD(x) (0x01 << (2 * (x)))
-#define BIT_GPIOPUPDCTR1_GPIOxPU(x) ((x) + 1)
-#define MASK_GPIOPUPDCTR1_GPIOxPU(x) (0x01 << (((2 * (x)) + 1)))
-
-/* GPIO_EDR1 Fields */
-#define BIT_GPIO_EDR1_GPIOxFALLING(x) (2 * (x))
-#define MASK_GPIO_EDR1_GPIOxFALLING(x) (0x01 << (2 * (x)))
-#define BIT_GPIO_EDR1_GPIOxRISING(x) ((x) + 1)
-#define MASK_GPIO_EDR1_GPIOxRISING(x) (0x01 << (((2 * (x)) + 1)))
-
/* GPIO_SIH_CTRL Fields */
-#define BIT_GPIO_SIH_CTRL_EXCLEN (0x000)
-#define MASK_GPIO_SIH_CTRL_EXCLEN (0x00000001)
-#define BIT_GPIO_SIH_CTRL_PENDDIS (0x001)
-#define MASK_GPIO_SIH_CTRL_PENDDIS (0x00000002)
-#define BIT_GPIO_SIH_CTRL_COR (0x002)
-#define MASK_GPIO_SIH_CTRL_COR (0x00000004)
+#define MASK_GPIO_SIH_CTRL_EXCLEN BIT(0)
+#define MASK_GPIO_SIH_CTRL_PENDDIS BIT(1)
+#define MASK_GPIO_SIH_CTRL_COR BIT(2)
/* GPIO_CTRL Fields */
-#define BIT_GPIO_CTRL_GPIO0CD1 (0x000)
-#define MASK_GPIO_CTRL_GPIO0CD1 (0x00000001)
-#define BIT_GPIO_CTRL_GPIO1CD2 (0x001)
-#define MASK_GPIO_CTRL_GPIO1CD2 (0x00000002)
-#define BIT_GPIO_CTRL_GPIO_ON (0x002)
-#define MASK_GPIO_CTRL_GPIO_ON (0x00000004)
+#define MASK_GPIO_CTRL_GPIO0CD1 BIT(0)
+#define MASK_GPIO_CTRL_GPIO1CD2 BIT(1)
+#define MASK_GPIO_CTRL_GPIO_ON BIT(2)
/* Mask for GPIO registers when aggregated into a 32-bit integer */
#define GPIO_32_MASK 0x0003ffff
.set_type = twl4030_gpio_irq_set_type,
};
-/*
- * These are the irqchip methods for the TWL4030 PIH GPIO module interrupt.
- * The PIH module doesn't have interrupt masking capability, so these
- * methods are NULL.
- */
-static void twl4030_gpio_module_ack(unsigned int irq) {}
-static void twl4030_gpio_module_mask(unsigned int irq) {}
-static void twl4030_gpio_module_unmask(unsigned int irq) {}
-static struct irq_chip twl4030_gpio_module_irq_chip = {
- .ack = twl4030_gpio_module_ack,
- .mask = twl4030_gpio_module_mask,
- .unmask = twl4030_gpio_module_unmask,
-};
/*
* To configure TWL4030 GPIO module registers
*/
static inline int gpio_twl4030_write(u8 address, u8 data)
{
- int ret = 0;
-
- ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
- return ret;
+ return twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
}
/*
int ret = 0;
ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
- if (ret >= 0)
- ret = data;
- return ret;
+ return (ret < 0) ? ret : data;
}
/*
return ret;
mutex_lock(&gpio_lock);
- if (gpio_usage_count & (0x1 << gpio)) {
+ if (gpio_usage_count & BIT(gpio)) {
ret = -EBUSY;
} else {
/* First time usage? - switch on GPIO module */
ret = gpio_twl4030_write(REG_GPIO_SIH_CTRL, 0x00);
}
if (!ret)
- gpio_usage_count |= (0x1 << gpio);
+ gpio_usage_count |= BIT(gpio);
else
gpio_free(twl_gpiochip.base + gpio);
}
mutex_lock(&gpio_lock);
- if ((gpio_usage_count & (0x1 << gpio)) == 0) {
+ if ((gpio_usage_count & BIT(gpio)) == 0) {
ret = -EPERM;
} else {
- gpio_usage_count &= ~(0x1 << gpio);
+ gpio_usage_count &= ~BIT(gpio);
gpio_free(twl_gpiochip.base + gpio);
}
}
EXPORT_SYMBOL(twl4030_free_gpio);
-/*
- * Set direction for TWL4030 GPIO
- */
static int twl4030_set_gpio_direction(int gpio, int is_input)
{
- u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
- u8 d_msk = MASK_GPIODATADIR_GPIOxDIR(GET_GPIO_DATA_OFF(gpio));
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
u8 reg = 0;
u8 base = REG_GPIODATADIR1 + d_bnk;
int ret = 0;
- if (unlikely(!(gpio_usage_count & (0x1 << gpio))))
- return -EPERM;
-
mutex_lock(&gpio_lock);
ret = gpio_twl4030_read(base);
if (ret >= 0) {
if (is_input)
- reg = (u8) ((ret) & ~(d_msk));
+ reg = ret & ~d_msk;
else
- reg = (u8) ((ret) | (d_msk));
+ reg = ret | d_msk;
ret = gpio_twl4030_write(base, reg);
}
return ret;
}
-/*
- * To enable/disable GPIO pin on TWL4030
- */
static int twl4030_set_gpio_dataout(int gpio, int enable)
{
- u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
- u8 d_msk = MASK_GPIODATAOUT_GPIOxOUT(GET_GPIO_DATA_OFF(gpio));
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
u8 base = 0;
- int ret = 0;
-
- if (unlikely(!(gpio_usage_count & (0x1 << gpio))))
- return -EPERM;
if (enable)
base = REG_SETGPIODATAOUT1 + d_bnk;
else
base = REG_CLEARGPIODATAOUT1 + d_bnk;
- mutex_lock(&gpio_lock);
- ret = gpio_twl4030_write(base, d_msk);
- mutex_unlock(&gpio_lock);
- return ret;
+ return gpio_twl4030_write(base, d_msk);
}
-/*
- * To get the status of a GPIO pin on TWL4030
- */
int twl4030_get_gpio_datain(int gpio)
{
- u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
- u8 d_off = BIT_GPIODATAIN_GPIOxIN(GET_GPIO_DATA_OFF(gpio));
+ u8 d_bnk = gpio >> 3;
+ u8 d_off = gpio & 0x7;
u8 base = 0;
int ret = 0;
if (unlikely((gpio >= TWL4030_GPIO_MAX)
- || !(gpio_usage_count & (0x1 << gpio))))
+ || !(gpio_usage_count & BIT(gpio))))
return -EPERM;
base = REG_GPIODATAIN1 + d_bnk;
- mutex_lock(&gpio_lock);
ret = gpio_twl4030_read(base);
- mutex_unlock(&gpio_lock);
if (ret > 0)
ret = (ret >> d_off) & 0x1;
static int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
{
- u8 c_bnk = GET_GPIO_CTL_BANK(gpio);
- u8 c_off = GET_GPIO_CTL_OFF(gpio);
+ u8 c_bnk = gpio >> 2;
+ u8 c_off = (gpio & 0x3) * 2;
u8 c_msk = 0;
u8 reg = 0;
u8 base = 0;
base = REG_GPIO_EDR1 + c_bnk;
if (edge & IRQ_TYPE_EDGE_RISING)
- c_msk |= MASK_GPIO_EDR1_GPIOxRISING(c_off);
+ c_msk |= BIT(c_off + 1);
if (edge & IRQ_TYPE_EDGE_FALLING)
- c_msk |= MASK_GPIO_EDR1_GPIOxFALLING(c_off);
+ c_msk |= BIT(c_off);
mutex_lock(&gpio_lock);
ret = gpio_twl4030_read(base);
if (ret >= 0) {
/* clear the previous rising/falling values */
reg = (u8) ret;
- reg &= ~(MASK_GPIO_EDR1_GPIOxFALLING(c_off)
- | MASK_GPIO_EDR1_GPIOxRISING(c_off));
+ reg &= ~(0x3 << c_off);
reg |= c_msk;
ret = gpio_twl4030_write(base, reg);
}
*/
int twl4030_set_gpio_debounce(int gpio, int enable)
{
- u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
- u8 d_msk = MASK_GPIO_DEBEN_GPIOxDEB(GET_GPIO_DATA_OFF(gpio));
+ u8 d_bnk = gpio >> 3;
+ u8 d_msk = BIT(gpio & 0x7);
u8 reg = 0;
u8 base = 0;
int ret = 0;
if (unlikely((gpio >= TWL4030_GPIO_MAX)
- || !(gpio_usage_count & (0x1 << gpio))))
+ || !(gpio_usage_count & BIT(gpio))))
return -EPERM;
base = REG_GPIO_DEBEN1 + d_bnk;
ret = gpio_twl4030_read(base);
if (ret >= 0) {
if (enable)
- reg = (u8) ((ret) | (d_msk));
+ reg = ret | d_msk;
else
- reg = (u8) ((ret) & ~(d_msk));
+ reg = ret & ~d_msk;
ret = gpio_twl4030_write(base, reg);
}
/* Only GPIO 0 or 1 can be used for CD feature.. */
if (unlikely((gpio >= TWL4030_GPIO_MAX)
- || !(gpio_usage_count & (0x1 << gpio))
+ || !(gpio_usage_count & BIT(gpio))
|| (gpio >= TWL4030_GPIO_MAX_CD))) {
return -EPERM;
}
* Install an irq handler to demultiplex the gpio module
* interrupt.
*/
- set_irq_chip(irq, &twl4030_gpio_module_irq_chip);
set_irq_chained_handler(irq, do_twl4030_gpio_module_irq);
wake_up_process(gpio_unmask_thread);