2011-02-09 11:02:35 +05:30
/*
* Copyright ( C ) ST - Ericsson SA 2011
*
* Author : BIBEK BASU < bibek . basu @ stericsson . com >
* License terms : GNU General Public License ( GPL ) version 2
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/gpio.h>
# include <linux/irq.h>
# include <linux/interrupt.h>
# include <linux/mfd/ab8500.h>
# include <linux/mfd/abx500.h>
# include <linux/mfd/ab8500/gpio.h>
/*
* GPIO registers offset
* Bank : 0x10
*/
# define AB8500_GPIO_SEL1_REG 0x00
# define AB8500_GPIO_SEL2_REG 0x01
# define AB8500_GPIO_SEL3_REG 0x02
# define AB8500_GPIO_SEL4_REG 0x03
# define AB8500_GPIO_SEL5_REG 0x04
# define AB8500_GPIO_SEL6_REG 0x05
# define AB8500_GPIO_DIR1_REG 0x10
# define AB8500_GPIO_DIR2_REG 0x11
# define AB8500_GPIO_DIR3_REG 0x12
# define AB8500_GPIO_DIR4_REG 0x13
# define AB8500_GPIO_DIR5_REG 0x14
# define AB8500_GPIO_DIR6_REG 0x15
# define AB8500_GPIO_OUT1_REG 0x20
# define AB8500_GPIO_OUT2_REG 0x21
# define AB8500_GPIO_OUT3_REG 0x22
# define AB8500_GPIO_OUT4_REG 0x23
# define AB8500_GPIO_OUT5_REG 0x24
# define AB8500_GPIO_OUT6_REG 0x25
# define AB8500_GPIO_PUD1_REG 0x30
# define AB8500_GPIO_PUD2_REG 0x31
# define AB8500_GPIO_PUD3_REG 0x32
# define AB8500_GPIO_PUD4_REG 0x33
# define AB8500_GPIO_PUD5_REG 0x34
# define AB8500_GPIO_PUD6_REG 0x35
# define AB8500_GPIO_IN1_REG 0x40
# define AB8500_GPIO_IN2_REG 0x41
# define AB8500_GPIO_IN3_REG 0x42
# define AB8500_GPIO_IN4_REG 0x43
# define AB8500_GPIO_IN5_REG 0x44
# define AB8500_GPIO_IN6_REG 0x45
# define AB8500_GPIO_ALTFUN_REG 0x45
# define ALTFUN_REG_INDEX 6
# define AB8500_NUM_GPIO 42
# define AB8500_NUM_VIR_GPIO_IRQ 16
enum ab8500_gpio_action {
NONE ,
STARTUP ,
SHUTDOWN ,
MASK ,
UNMASK
} ;
struct ab8500_gpio {
struct gpio_chip chip ;
struct ab8500 * parent ;
struct device * dev ;
struct mutex lock ;
u32 irq_base ;
enum ab8500_gpio_action irq_action ;
u16 rising ;
u16 falling ;
} ;
/**
* to_ab8500_gpio ( ) - get the pointer to ab8500_gpio
* @ chip : Member of the structure ab8500_gpio
*/
static inline struct ab8500_gpio * to_ab8500_gpio ( struct gpio_chip * chip )
{
return container_of ( chip , struct ab8500_gpio , chip ) ;
}
static int ab8500_gpio_set_bits ( struct gpio_chip * chip , u8 reg ,
unsigned offset , int val )
{
struct ab8500_gpio * ab8500_gpio = to_ab8500_gpio ( chip ) ;
u8 pos = offset % 8 ;
int ret ;
reg = reg + ( offset / 8 ) ;
ret = abx500_mask_and_set_register_interruptible ( ab8500_gpio - > dev ,
AB8500_MISC , reg , 1 < < pos , val < < pos ) ;
if ( ret < 0 )
dev_err ( ab8500_gpio - > dev , " %s write failed \n " , __func__ ) ;
return ret ;
}
/**
* ab8500_gpio_get ( ) - Get the particular GPIO value
* @ chip : Gpio device
* @ offset : GPIO number to read
*/
static int ab8500_gpio_get ( struct gpio_chip * chip , unsigned offset )
{
struct ab8500_gpio * ab8500_gpio = to_ab8500_gpio ( chip ) ;
u8 mask = 1 < < ( offset % 8 ) ;
u8 reg = AB8500_GPIO_OUT1_REG + ( offset / 8 ) ;
int ret ;
u8 data ;
ret = abx500_get_register_interruptible ( ab8500_gpio - > dev , AB8500_MISC ,
reg , & data ) ;
if ( ret < 0 ) {
dev_err ( ab8500_gpio - > dev , " %s read failed \n " , __func__ ) ;
return ret ;
}
return ( data & mask ) > > ( offset % 8 ) ;
}
static void ab8500_gpio_set ( struct gpio_chip * chip , unsigned offset , int val )
{
struct ab8500_gpio * ab8500_gpio = to_ab8500_gpio ( chip ) ;
int ret ;
/* Write the data */
ret = ab8500_gpio_set_bits ( chip , AB8500_GPIO_OUT1_REG , offset , 1 ) ;
if ( ret < 0 )
dev_err ( ab8500_gpio - > dev , " %s write failed \n " , __func__ ) ;
}
static int ab8500_gpio_direction_output ( struct gpio_chip * chip , unsigned offset ,
int val )
{
int ret ;
/* set direction as output */
ret = ab8500_gpio_set_bits ( chip , AB8500_GPIO_DIR1_REG , offset , 1 ) ;
if ( ret < 0 )
return ret ;
/* disable pull down */
ret = ab8500_gpio_set_bits ( chip , AB8500_GPIO_PUD1_REG , offset , 1 ) ;
if ( ret < 0 )
return ret ;
/* set the output as 1 or 0 */
return ab8500_gpio_set_bits ( chip , AB8500_GPIO_OUT1_REG , offset , val ) ;
}
static int ab8500_gpio_direction_input ( struct gpio_chip * chip , unsigned offset )
{
/* set the register as input */
return ab8500_gpio_set_bits ( chip , AB8500_GPIO_DIR1_REG , offset , 0 ) ;
}
static int ab8500_gpio_to_irq ( struct gpio_chip * chip , unsigned offset )
{
/*
* Only some GPIOs are interrupt capable , and they are
* organized in discontiguous clusters :
*
* GPIO6 to GPIO13
* GPIO24 and GPIO25
* GPIO36 to GPIO41
*/
static struct ab8500_gpio_irq_cluster {
int start ;
int end ;
} clusters [ ] = {
{ . start = 6 , . end = 13 } ,
{ . start = 24 , . end = 25 } ,
{ . start = 36 , . end = 41 } ,
} ;
struct ab8500_gpio * ab8500_gpio = to_ab8500_gpio ( chip ) ;
int base = ab8500_gpio - > irq_base ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( clusters ) ; i + + ) {
struct ab8500_gpio_irq_cluster * cluster = & clusters [ i ] ;
if ( offset > = cluster - > start & & offset < = cluster - > end )
return base + offset - cluster - > start ;
/* Advance by the number of gpios in this cluster */
base + = cluster - > end - cluster - > start + 1 ;
}
return - EINVAL ;
}
static struct gpio_chip ab8500gpio_chip = {
. label = " ab8500_gpio " ,
. owner = THIS_MODULE ,
. direction_input = ab8500_gpio_direction_input ,
. get = ab8500_gpio_get ,
. direction_output = ab8500_gpio_direction_output ,
. set = ab8500_gpio_set ,
. to_irq = ab8500_gpio_to_irq ,
} ;
static unsigned int irq_to_rising ( unsigned int irq )
{
struct ab8500_gpio * ab8500_gpio = get_irq_chip_data ( irq ) ;
int offset = irq - ab8500_gpio - > irq_base ;
int new_irq = offset + AB8500_INT_GPIO6R
+ ab8500_gpio - > parent - > irq_base ;
return new_irq ;
}
static unsigned int irq_to_falling ( unsigned int irq )
{
struct ab8500_gpio * ab8500_gpio = get_irq_chip_data ( irq ) ;
int offset = irq - ab8500_gpio - > irq_base ;
int new_irq = offset + AB8500_INT_GPIO6F
+ ab8500_gpio - > parent - > irq_base ;
return new_irq ;
}
static unsigned int rising_to_irq ( unsigned int irq , void * dev )
{
struct ab8500_gpio * ab8500_gpio = dev ;
int offset = irq - AB8500_INT_GPIO6R
- ab8500_gpio - > parent - > irq_base ;
int new_irq = offset + ab8500_gpio - > irq_base ;
return new_irq ;
}
static unsigned int falling_to_irq ( unsigned int irq , void * dev )
{
struct ab8500_gpio * ab8500_gpio = dev ;
int offset = irq - AB8500_INT_GPIO6F
- ab8500_gpio - > parent - > irq_base ;
int new_irq = offset + ab8500_gpio - > irq_base ;
return new_irq ;
}
/*
* IRQ handler
*/
static irqreturn_t handle_rising ( int irq , void * dev )
{
handle_nested_irq ( rising_to_irq ( irq , dev ) ) ;
return IRQ_HANDLED ;
}
static irqreturn_t handle_falling ( int irq , void * dev )
{
handle_nested_irq ( falling_to_irq ( irq , dev ) ) ;
return IRQ_HANDLED ;
}
static void ab8500_gpio_irq_lock ( unsigned int irq )
{
struct ab8500_gpio * ab8500_gpio = get_irq_chip_data ( irq ) ;
mutex_lock ( & ab8500_gpio - > lock ) ;
}
static void ab8500_gpio_irq_sync_unlock ( unsigned int irq )
{
struct ab8500_gpio * ab8500_gpio = get_irq_chip_data ( irq ) ;
int offset = irq - ab8500_gpio - > irq_base ;
bool rising = ab8500_gpio - > rising & BIT ( offset ) ;
bool falling = ab8500_gpio - > falling & BIT ( offset ) ;
int ret ;
switch ( ab8500_gpio - > irq_action ) {
case STARTUP :
if ( rising )
ret = request_threaded_irq ( irq_to_rising ( irq ) ,
NULL , handle_rising ,
IRQF_TRIGGER_RISING ,
" ab8500-gpio-r " , ab8500_gpio ) ;
if ( falling )
ret = request_threaded_irq ( irq_to_falling ( irq ) ,
NULL , handle_falling ,
IRQF_TRIGGER_FALLING ,
" ab8500-gpio-f " , ab8500_gpio ) ;
break ;
case SHUTDOWN :
if ( rising )
free_irq ( irq_to_rising ( irq ) , ab8500_gpio ) ;
if ( falling )
free_irq ( irq_to_falling ( irq ) , ab8500_gpio ) ;
break ;
case MASK :
if ( rising )
disable_irq ( irq_to_rising ( irq ) ) ;
if ( falling )
disable_irq ( irq_to_falling ( irq ) ) ;
break ;
case UNMASK :
if ( rising )
enable_irq ( irq_to_rising ( irq ) ) ;
if ( falling )
enable_irq ( irq_to_falling ( irq ) ) ;
break ;
case NONE :
break ;
}
ab8500_gpio - > irq_action = NONE ;
ab8500_gpio - > rising & = ~ ( BIT ( offset ) ) ;
ab8500_gpio - > falling & = ~ ( BIT ( offset ) ) ;
mutex_unlock ( & ab8500_gpio - > lock ) ;
}
static void ab8500_gpio_irq_mask ( unsigned int irq )
{
struct ab8500_gpio * ab8500_gpio = get_irq_chip_data ( irq ) ;
ab8500_gpio - > irq_action = MASK ;
}
static void ab8500_gpio_irq_unmask ( unsigned int irq )
{
struct ab8500_gpio * ab8500_gpio = get_irq_chip_data ( irq ) ;
ab8500_gpio - > irq_action = UNMASK ;
}
static int ab8500_gpio_irq_set_type ( unsigned int irq , unsigned int type )
{
struct ab8500_gpio * ab8500_gpio = get_irq_chip_data ( irq ) ;
int offset = irq - ab8500_gpio - > irq_base ;
if ( type = = IRQ_TYPE_EDGE_BOTH ) {
ab8500_gpio - > rising = BIT ( offset ) ;
ab8500_gpio - > falling = BIT ( offset ) ;
} else if ( type = = IRQ_TYPE_EDGE_RISING ) {
ab8500_gpio - > rising = BIT ( offset ) ;
} else {
ab8500_gpio - > falling = BIT ( offset ) ;
}
return 0 ;
}
unsigned int ab8500_gpio_irq_startup ( unsigned int irq )
{
struct ab8500_gpio * ab8500_gpio = get_irq_chip_data ( irq ) ;
ab8500_gpio - > irq_action = STARTUP ;
return 0 ;
}
void ab8500_gpio_irq_shutdown ( unsigned int irq )
{
struct ab8500_gpio * ab8500_gpio = get_irq_chip_data ( irq ) ;
ab8500_gpio - > irq_action = SHUTDOWN ;
}
static struct irq_chip ab8500_gpio_irq_chip = {
. name = " ab8500-gpio " ,
. startup = ab8500_gpio_irq_startup ,
. shutdown = ab8500_gpio_irq_shutdown ,
. bus_lock = ab8500_gpio_irq_lock ,
. bus_sync_unlock = ab8500_gpio_irq_sync_unlock ,
. mask = ab8500_gpio_irq_mask ,
. unmask = ab8500_gpio_irq_unmask ,
. set_type = ab8500_gpio_irq_set_type ,
} ;
static int ab8500_gpio_irq_init ( struct ab8500_gpio * ab8500_gpio )
{
u32 base = ab8500_gpio - > irq_base ;
int irq ;
for ( irq = base ; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq + + ) {
set_irq_chip_data ( irq , ab8500_gpio ) ;
set_irq_chip_and_handler ( irq , & ab8500_gpio_irq_chip ,
handle_simple_irq ) ;
set_irq_nested_thread ( irq , 1 ) ;
# ifdef CONFIG_ARM
set_irq_flags ( irq , IRQF_VALID ) ;
# else
set_irq_noprobe ( irq ) ;
# endif
}
return 0 ;
}
static void ab8500_gpio_irq_remove ( struct ab8500_gpio * ab8500_gpio )
{
int base = ab8500_gpio - > irq_base ;
int irq ;
for ( irq = base ; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq + + ) {
# ifdef CONFIG_ARM
set_irq_flags ( irq , 0 ) ;
# endif
set_irq_chip_and_handler ( irq , NULL , NULL ) ;
set_irq_chip_data ( irq , NULL ) ;
}
}
static int __devinit ab8500_gpio_probe ( struct platform_device * pdev )
{
struct ab8500_platform_data * ab8500_pdata =
dev_get_platdata ( pdev - > dev . parent ) ;
struct ab8500_gpio_platform_data * pdata ;
struct ab8500_gpio * ab8500_gpio ;
int ret ;
int i ;
pdata = ab8500_pdata - > gpio ;
if ( ! pdata ) {
dev_err ( & pdev - > dev , " gpio platform data missing \n " ) ;
return - ENODEV ;
}
ab8500_gpio = kzalloc ( sizeof ( struct ab8500_gpio ) , GFP_KERNEL ) ;
if ( ab8500_gpio = = NULL ) {
dev_err ( & pdev - > dev , " failed to allocate memory \n " ) ;
return - ENOMEM ;
}
ab8500_gpio - > dev = & pdev - > dev ;
ab8500_gpio - > parent = dev_get_drvdata ( pdev - > dev . parent ) ;
ab8500_gpio - > chip = ab8500gpio_chip ;
ab8500_gpio - > chip . ngpio = AB8500_NUM_GPIO ;
ab8500_gpio - > chip . dev = & pdev - > dev ;
ab8500_gpio - > chip . base = pdata - > gpio_base ;
ab8500_gpio - > irq_base = pdata - > irq_base ;
/* initialize the lock */
mutex_init ( & ab8500_gpio - > lock ) ;
/*
* AB8500 core will handle and clear the IRQ
* configre GPIO based on config - reg value .
* These values are for selecting the PINs as
* GPIO or alternate function
*/
for ( i = AB8500_GPIO_SEL1_REG ; i < = AB8500_GPIO_SEL6_REG ; i + + ) {
ret = abx500_set_register_interruptible ( ab8500_gpio - > dev ,
AB8500_MISC , i ,
pdata - > config_reg [ i ] ) ;
if ( ret < 0 )
goto out_free ;
}
ret = abx500_set_register_interruptible ( ab8500_gpio - > dev , AB8500_MISC ,
AB8500_GPIO_ALTFUN_REG ,
pdata - > config_reg [ ALTFUN_REG_INDEX ] ) ;
if ( ret < 0 )
goto out_free ;
ret = ab8500_gpio_irq_init ( ab8500_gpio ) ;
if ( ret )
goto out_free ;
ret = gpiochip_add ( & ab8500_gpio - > chip ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " unable to add gpiochip: %d \n " ,
ret ) ;
goto out_rem_irq ;
}
platform_set_drvdata ( pdev , ab8500_gpio ) ;
return 0 ;
out_rem_irq :
ab8500_gpio_irq_remove ( ab8500_gpio ) ;
out_free :
mutex_destroy ( & ab8500_gpio - > lock ) ;
kfree ( ab8500_gpio ) ;
return ret ;
}
/*
* ab8500_gpio_remove ( ) - remove Ab8500 - gpio driver
* @ pdev : Platform device registered
*/
static int __devexit ab8500_gpio_remove ( struct platform_device * pdev )
{
struct ab8500_gpio * ab8500_gpio = platform_get_drvdata ( pdev ) ;
int ret ;
ret = gpiochip_remove ( & ab8500_gpio - > chip ) ;
if ( ret < 0 ) {
2011-04-23 20:38:19 -07:00
dev_err ( ab8500_gpio - > dev , " unable to remove gpiochip: %d \n " ,
ret ) ;
2011-02-09 11:02:35 +05:30
return ret ;
}
platform_set_drvdata ( pdev , NULL ) ;
mutex_destroy ( & ab8500_gpio - > lock ) ;
kfree ( ab8500_gpio ) ;
return 0 ;
}
static struct platform_driver ab8500_gpio_driver = {
. driver = {
. name = " ab8500-gpio " ,
. owner = THIS_MODULE ,
} ,
. probe = ab8500_gpio_probe ,
. remove = __devexit_p ( ab8500_gpio_remove ) ,
} ;
static int __init ab8500_gpio_init ( void )
{
return platform_driver_register ( & ab8500_gpio_driver ) ;
}
arch_initcall ( ab8500_gpio_init ) ;
static void __exit ab8500_gpio_exit ( void )
{
platform_driver_unregister ( & ab8500_gpio_driver ) ;
}
module_exit ( ab8500_gpio_exit ) ;
MODULE_AUTHOR ( " BIBEK BASU <bibek.basu@stericsson.com> " ) ;
2011-04-23 20:38:19 -07:00
MODULE_DESCRIPTION ( " Driver allows to use AB8500 unused pins to be used as GPIO " ) ;
2011-07-28 22:16:49 +08:00
MODULE_ALIAS ( " platform:ab8500-gpio " ) ;
2011-02-09 11:02:35 +05:30
MODULE_LICENSE ( " GPL v2 " ) ;