2008-02-05 09:28:26 +03:00
/*
2008-02-06 12:39:04 +03:00
* pca953x . c - 4 / 8 / 16 bit I / O ports
2008-02-05 09:28:26 +03:00
*
* Copyright ( C ) 2005 Ben Gardner < bgardner @ wabtec . com >
* Copyright ( C ) 2007 Marvell International Ltd .
*
* Derived from drivers / i2c / chips / pca9539 . c
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; version 2 of the License .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/i2c.h>
2008-02-06 12:39:02 +03:00
# include <linux/i2c/pca953x.h>
2008-02-05 09:28:26 +03:00
# include <asm/gpio.h>
2008-02-06 12:39:04 +03:00
# define PCA953X_INPUT 0
# define PCA953X_OUTPUT 1
# define PCA953X_INVERT 2
# define PCA953X_DIRECTION 3
2008-02-05 09:28:26 +03:00
2008-04-30 01:11:40 +04:00
static const struct i2c_device_id pca953x_id [ ] = {
2008-02-06 12:39:04 +03:00
{ " pca9534 " , 8 , } ,
{ " pca9535 " , 16 , } ,
{ " pca9536 " , 4 , } ,
{ " pca9537 " , 4 , } ,
{ " pca9538 " , 8 , } ,
{ " pca9539 " , 16 , } ,
2008-05-24 00:04:42 +04:00
{ " pca9554 " , 8 , } ,
2008-05-01 15:35:10 +04:00
{ " pca9555 " , 16 , } ,
{ " pca9557 " , 8 , } ,
2009-01-07 01:42:27 +03:00
2008-07-04 20:59:37 +04:00
{ " max7310 " , 8 , } ,
2009-01-07 01:42:27 +03:00
{ " pca6107 " , 8 , } ,
{ " tca6408 " , 8 , } ,
{ " tca6416 " , 16 , } ,
/* NYET: { "tca6424", 24, }, */
2008-04-30 01:11:40 +04:00
{ }
2008-02-06 12:39:04 +03:00
} ;
2008-04-30 01:11:40 +04:00
MODULE_DEVICE_TABLE ( i2c , pca953x_id ) ;
2008-02-05 09:28:26 +03:00
2008-02-06 12:39:03 +03:00
struct pca953x_chip {
2008-02-05 09:28:26 +03:00
unsigned gpio_start ;
uint16_t reg_output ;
uint16_t reg_direction ;
struct i2c_client * client ;
struct gpio_chip gpio_chip ;
} ;
2008-02-06 12:39:03 +03:00
static int pca953x_write_reg ( struct pca953x_chip * chip , int reg , uint16_t val )
2008-02-05 09:28:26 +03:00
{
2008-02-06 12:39:04 +03:00
int ret ;
if ( chip - > gpio_chip . ngpio < = 8 )
ret = i2c_smbus_write_byte_data ( chip - > client , reg , val ) ;
2008-02-05 09:28:26 +03:00
else
2008-02-06 12:39:04 +03:00
ret = i2c_smbus_write_word_data ( chip - > client , reg < < 1 , val ) ;
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev , " failed writing register \n " ) ;
2009-01-07 01:42:27 +03:00
return ret ;
2008-02-06 12:39:04 +03:00
}
return 0 ;
2008-02-05 09:28:26 +03:00
}
2008-02-06 12:39:03 +03:00
static int pca953x_read_reg ( struct pca953x_chip * chip , int reg , uint16_t * val )
2008-02-05 09:28:26 +03:00
{
int ret ;
2008-02-06 12:39:04 +03:00
if ( chip - > gpio_chip . ngpio < = 8 )
ret = i2c_smbus_read_byte_data ( chip - > client , reg ) ;
else
ret = i2c_smbus_read_word_data ( chip - > client , reg < < 1 ) ;
2008-02-05 09:28:26 +03:00
if ( ret < 0 ) {
dev_err ( & chip - > client - > dev , " failed reading register \n " ) ;
2009-01-07 01:42:27 +03:00
return ret ;
2008-02-05 09:28:26 +03:00
}
* val = ( uint16_t ) ret ;
return 0 ;
}
2008-02-06 12:39:03 +03:00
static int pca953x_gpio_direction_input ( struct gpio_chip * gc , unsigned off )
2008-02-05 09:28:26 +03:00
{
2008-02-06 12:39:03 +03:00
struct pca953x_chip * chip ;
2008-02-05 09:28:26 +03:00
uint16_t reg_val ;
int ret ;
2008-02-06 12:39:03 +03:00
chip = container_of ( gc , struct pca953x_chip , gpio_chip ) ;
2008-02-05 09:28:26 +03:00
reg_val = chip - > reg_direction | ( 1u < < off ) ;
2008-02-06 12:39:03 +03:00
ret = pca953x_write_reg ( chip , PCA953X_DIRECTION , reg_val ) ;
2008-02-05 09:28:26 +03:00
if ( ret )
return ret ;
chip - > reg_direction = reg_val ;
return 0 ;
}
2008-02-06 12:39:03 +03:00
static int pca953x_gpio_direction_output ( struct gpio_chip * gc ,
2008-02-05 09:28:26 +03:00
unsigned off , int val )
{
2008-02-06 12:39:03 +03:00
struct pca953x_chip * chip ;
2008-02-05 09:28:26 +03:00
uint16_t reg_val ;
int ret ;
2008-02-06 12:39:03 +03:00
chip = container_of ( gc , struct pca953x_chip , gpio_chip ) ;
2008-02-05 09:28:26 +03:00
/* set output level */
if ( val )
reg_val = chip - > reg_output | ( 1u < < off ) ;
else
reg_val = chip - > reg_output & ~ ( 1u < < off ) ;
2008-02-06 12:39:03 +03:00
ret = pca953x_write_reg ( chip , PCA953X_OUTPUT , reg_val ) ;
2008-02-05 09:28:26 +03:00
if ( ret )
return ret ;
chip - > reg_output = reg_val ;
/* then direction */
reg_val = chip - > reg_direction & ~ ( 1u < < off ) ;
2008-02-06 12:39:03 +03:00
ret = pca953x_write_reg ( chip , PCA953X_DIRECTION , reg_val ) ;
2008-02-05 09:28:26 +03:00
if ( ret )
return ret ;
chip - > reg_direction = reg_val ;
return 0 ;
}
2008-02-06 12:39:03 +03:00
static int pca953x_gpio_get_value ( struct gpio_chip * gc , unsigned off )
2008-02-05 09:28:26 +03:00
{
2008-02-06 12:39:03 +03:00
struct pca953x_chip * chip ;
2008-02-05 09:28:26 +03:00
uint16_t reg_val ;
int ret ;
2008-02-06 12:39:03 +03:00
chip = container_of ( gc , struct pca953x_chip , gpio_chip ) ;
2008-02-05 09:28:26 +03:00
2008-02-06 12:39:03 +03:00
ret = pca953x_read_reg ( chip , PCA953X_INPUT , & reg_val ) ;
2008-02-05 09:28:26 +03:00
if ( ret < 0 ) {
/* NOTE: diagnostic already emitted; that's all we should
* do unless gpio_ * _value_cansleep ( ) calls become different
* from their nonsleeping siblings ( and report faults ) .
*/
return 0 ;
}
return ( reg_val & ( 1u < < off ) ) ? 1 : 0 ;
}
2008-02-06 12:39:03 +03:00
static void pca953x_gpio_set_value ( struct gpio_chip * gc , unsigned off , int val )
2008-02-05 09:28:26 +03:00
{
2008-02-06 12:39:03 +03:00
struct pca953x_chip * chip ;
2008-02-05 09:28:26 +03:00
uint16_t reg_val ;
int ret ;
2008-02-06 12:39:03 +03:00
chip = container_of ( gc , struct pca953x_chip , gpio_chip ) ;
2008-02-05 09:28:26 +03:00
if ( val )
reg_val = chip - > reg_output | ( 1u < < off ) ;
else
reg_val = chip - > reg_output & ~ ( 1u < < off ) ;
2008-02-06 12:39:03 +03:00
ret = pca953x_write_reg ( chip , PCA953X_OUTPUT , reg_val ) ;
2008-02-05 09:28:26 +03:00
if ( ret )
return ;
chip - > reg_output = reg_val ;
}
2008-02-06 12:39:04 +03:00
static void pca953x_setup_gpio ( struct pca953x_chip * chip , int gpios )
2008-02-05 09:28:26 +03:00
{
struct gpio_chip * gc ;
gc = & chip - > gpio_chip ;
2008-02-06 12:39:03 +03:00
gc - > direction_input = pca953x_gpio_direction_input ;
gc - > direction_output = pca953x_gpio_direction_output ;
gc - > get = pca953x_gpio_get_value ;
gc - > set = pca953x_gpio_set_value ;
2008-03-10 21:43:48 +03:00
gc - > can_sleep = 1 ;
2008-02-05 09:28:26 +03:00
gc - > base = chip - > gpio_start ;
2008-02-06 12:39:04 +03:00
gc - > ngpio = gpios ;
gc - > label = chip - > client - > name ;
gpio: sysfs interface
This adds a simple sysfs interface for GPIOs.
/sys/class/gpio
/export ... asks the kernel to export a GPIO to userspace
/unexport ... to return a GPIO to the kernel
/gpioN ... for each exported GPIO #N
/value ... always readable, writes fail for input GPIOs
/direction ... r/w as: in, out (default low); write high, low
/gpiochipN ... for each gpiochip; #N is its first GPIO
/base ... (r/o) same as N
/label ... (r/o) descriptive, not necessarily unique
/ngpio ... (r/o) number of GPIOs; numbered N .. N+(ngpio - 1)
GPIOs claimed by kernel code may be exported by its owner using a new
gpio_export() call, which should be most useful for driver debugging.
Such exports may optionally be done without a "direction" attribute.
Userspace may ask to take over a GPIO by writing to a sysfs control file,
helping to cope with incomplete board support or other "one-off"
requirements that don't merit full kernel support:
echo 23 > /sys/class/gpio/export
... will gpio_request(23, "sysfs") and gpio_export(23);
use /sys/class/gpio/gpio-23/direction to (re)configure it,
when that GPIO can be used as both input and output.
echo 23 > /sys/class/gpio/unexport
... will gpio_free(23), when it was exported as above
The extra D-space footprint is a few hundred bytes, except for the sysfs
resources associated with each exported GPIO. The additional I-space
footprint is about two thirds of the current size of gpiolib (!). Since
no /dev node creation is involved, no "udev" support is needed.
Related changes:
* This adds a device pointer to "struct gpio_chip". When GPIO
providers initialize that, sysfs gpio class devices become children of
that device instead of being "virtual" devices.
* The (few) gpio_chip providers which have such a device node have
been updated.
* Some gpio_chip drivers also needed to update their module "owner"
field ... for which missing kerneldoc was added.
* Some gpio_chips don't support input GPIOs. Those GPIOs are now
flagged appropriately when the chip is registered.
Based on previous patches, and discussion both on and off LKML.
A Documentation/ABI/testing/sysfs-gpio update is ready to submit once this
merges to mainline.
[akpm@linux-foundation.org: a few maintenance build fixes]
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Cc: Guennadi Liakhovetski <g.liakhovetski@pengutronix.de>
Cc: Greg KH <greg@kroah.com>
Cc: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-07-25 12:46:07 +04:00
gc - > dev = & chip - > client - > dev ;
2008-04-28 13:14:45 +04:00
gc - > owner = THIS_MODULE ;
2008-02-05 09:28:26 +03:00
}
2008-04-30 01:11:39 +04:00
static int __devinit pca953x_probe ( struct i2c_client * client ,
2008-04-30 01:11:40 +04:00
const struct i2c_device_id * id )
2008-02-05 09:28:26 +03:00
{
2008-02-06 12:39:03 +03:00
struct pca953x_platform_data * pdata ;
struct pca953x_chip * chip ;
2008-05-01 15:35:10 +04:00
int ret ;
2008-02-05 09:28:26 +03:00
pdata = client - > dev . platform_data ;
2009-01-16 00:50:45 +03:00
if ( pdata = = NULL ) {
dev_dbg ( & client - > dev , " no platform data \n " ) ;
return - EINVAL ;
}
2008-02-05 09:28:26 +03:00
2008-02-06 12:39:03 +03:00
chip = kzalloc ( sizeof ( struct pca953x_chip ) , GFP_KERNEL ) ;
2008-02-05 09:28:26 +03:00
if ( chip = = NULL )
return - ENOMEM ;
chip - > client = client ;
chip - > gpio_start = pdata - > gpio_base ;
/* initialize cached registers from their original values.
* we can ' t share this chip with another i2c master .
*/
2008-02-06 12:39:04 +03:00
pca953x_setup_gpio ( chip , id - > driver_data ) ;
2008-02-06 12:39:03 +03:00
ret = pca953x_read_reg ( chip , PCA953X_OUTPUT , & chip - > reg_output ) ;
2008-02-05 09:28:26 +03:00
if ( ret )
goto out_failed ;
2008-02-06 12:39:03 +03:00
ret = pca953x_read_reg ( chip , PCA953X_DIRECTION , & chip - > reg_direction ) ;
2008-02-05 09:28:26 +03:00
if ( ret )
goto out_failed ;
/* set platform specific polarity inversion */
2008-02-06 12:39:03 +03:00
ret = pca953x_write_reg ( chip , PCA953X_INVERT , pdata - > invert ) ;
2008-02-05 09:28:26 +03:00
if ( ret )
goto out_failed ;
2008-02-06 12:39:04 +03:00
ret = gpiochip_add ( & chip - > gpio_chip ) ;
2008-02-05 09:28:26 +03:00
if ( ret )
goto out_failed ;
if ( pdata - > setup ) {
ret = pdata - > setup ( client , chip - > gpio_chip . base ,
chip - > gpio_chip . ngpio , pdata - > context ) ;
if ( ret < 0 )
dev_warn ( & client - > dev , " setup failed, %d \n " , ret ) ;
}
i2c_set_clientdata ( client , chip ) ;
return 0 ;
out_failed :
kfree ( chip ) ;
return ret ;
}
2008-02-06 12:39:03 +03:00
static int pca953x_remove ( struct i2c_client * client )
2008-02-05 09:28:26 +03:00
{
2008-02-06 12:39:03 +03:00
struct pca953x_platform_data * pdata = client - > dev . platform_data ;
struct pca953x_chip * chip = i2c_get_clientdata ( client ) ;
2008-02-05 09:28:26 +03:00
int ret = 0 ;
if ( pdata - > teardown ) {
ret = pdata - > teardown ( client , chip - > gpio_chip . base ,
chip - > gpio_chip . ngpio , pdata - > context ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " %s failed, %d \n " ,
" teardown " , ret ) ;
return ret ;
}
}
ret = gpiochip_remove ( & chip - > gpio_chip ) ;
if ( ret ) {
dev_err ( & client - > dev , " %s failed, %d \n " ,
" gpiochip_remove() " , ret ) ;
return ret ;
}
kfree ( chip ) ;
return 0 ;
}
2008-02-06 12:39:03 +03:00
static struct i2c_driver pca953x_driver = {
2008-02-05 09:28:26 +03:00
. driver = {
2008-02-06 12:39:03 +03:00
. name = " pca953x " ,
2008-02-05 09:28:26 +03:00
} ,
2008-02-06 12:39:03 +03:00
. probe = pca953x_probe ,
. remove = pca953x_remove ,
2008-04-30 01:11:40 +04:00
. id_table = pca953x_id ,
2008-02-05 09:28:26 +03:00
} ;
2008-02-06 12:39:03 +03:00
static int __init pca953x_init ( void )
2008-02-05 09:28:26 +03:00
{
2008-02-06 12:39:03 +03:00
return i2c_add_driver ( & pca953x_driver ) ;
2008-02-05 09:28:26 +03:00
}
2008-10-16 09:03:13 +04:00
/* register after i2c postcore initcall and before
* subsys initcalls that may rely on these GPIOs
*/
subsys_initcall ( pca953x_init ) ;
2008-02-05 09:28:26 +03:00
2008-02-06 12:39:03 +03:00
static void __exit pca953x_exit ( void )
2008-02-05 09:28:26 +03:00
{
2008-02-06 12:39:03 +03:00
i2c_del_driver ( & pca953x_driver ) ;
2008-02-05 09:28:26 +03:00
}
2008-02-06 12:39:03 +03:00
module_exit ( pca953x_exit ) ;
2008-02-05 09:28:26 +03:00
MODULE_AUTHOR ( " eric miao <eric.miao@marvell.com> " ) ;
2008-02-06 12:39:03 +03:00
MODULE_DESCRIPTION ( " GPIO expander driver for PCA953x " ) ;
2008-02-05 09:28:26 +03:00
MODULE_LICENSE ( " GPL " ) ;