twl4030: new-style driver conversion
PATCH 1/2 twl4030: new-style driver conversion
More updates preparing for upstream merge of twl4030 driver:
Basic fixes
- twl4030-core becomes a new-style I2C driver
- declare and use platform_data structure for that core
- stop hard-wiring the irq numbers
- check functionality that's really used: I2C, not SMBus
Cleanup:
- remove needless "client string"
- remove some fake "bool" types
- include catalog part numbers (TPS659{5,3,2}0)
- diagnostics should identify the driver!
To use this, all boards with these chips will need to declare this chip when they declare their active I2C busses (done in a separate patch).
NOTE: the TWL4030_IRQ_* symbols still need to vanish, along with other global resource assignments associated with these chips.
--- drivers/i2c/chips/twl4030-core.c | 308 ++++++++++++++++--------------------- include/linux/i2c/twl4030.h | 11 + 2 files changed, 145 insertions(+), 174 deletions(-)
drivers/i2c/chips/twl4030-core.c +134 -174
@@ -1,5 +1,5 @@/* -* twl4030_core.c - driver for TWL4030 PM and audio CODEC device +* twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices * * Copyright (C) 2005-2006 Texas Instruments, Inc. *
@@ -56,14 +56,6 @@#define DRIVER_NAME "twl4030" -/* Macro Definitions */ -#define TWL_CLIENT_STRING "TWL4030-ID" -#define TWL_CLIENT_USED 1 -#define TWL_CLIENT_FREE 0 - -/* IRQ Flags */ -#define FREE 0 -#define USED 1/* Primary Interrupt Handler on TWL4030 Registers */
@@ -293,26 +285,18 @@ static const struct twl4030_mod_iregs __/* Helper functions */ -static int -twl4030_detect_client (struct i2c_adapter *adapter,unsigned char sid); -static int twl4030_attach_adapter (struct i2c_adapter *adapter); -static int twl4030_detach_client (struct i2c_client *client);static void do_twl4030_irq (unsigned int irq,irq_desc_t *desc); -static void twl_init_irq (void ); -/* Data Structures */ /* To have info on T2 IRQ substem activated or not */ -static unsigned char twl_irq_used =FREE ;static struct completion irq_event;/* Structure to define on TWL4030 Slave ID */ struct twl4030_client { -struct i2c_client client; -const char client_name[sizeof (TWL_CLIENT_STRING ) +1 ]; +struct i2c_client *client;const unsigned char address;const char adapter_index; -unsigned char inuse; +bool inuse;/* max numb of i2c_msg required is for read =2 */ struct i2c_msg xfer_msg[2 ];
@@ -356,36 +340,22 @@ static struct twl4030mapping twl4030_mapstatic struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES ] = { { .address =TWL4030_SLAVEID_ID0 , - .client_name =TWL_CLIENT_STRING "0" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, { .address =TWL4030_SLAVEID_ID1 , - .client_name =TWL_CLIENT_STRING "1" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, { .address =TWL4030_SLAVEID_ID2 , - .client_name =TWL_CLIENT_STRING "2" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, { .address =TWL4030_SLAVEID_ID3 , - .client_name =TWL_CLIENT_STRING "3" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, }; -/* One Client Driver , 4 Clients */ -static struct i2c_driver twl4030_driver = { - .driver = { - .name =DRIVER_NAME , - .owner =THIS_MODULE , - }, - .attach_adapter = twl4030_attach_adapter, - .detach_client = twl4030_detach_client, -}; -/* * TWL4030 doesn't have PIH mask, hence dummy function for mask * and unmask.
@@ -425,15 +395,14 @@ int twl4030_i2c_write(u8 mod_no, u8 *valstruct i2c_msg *msg;if (unlikely (mod_no >TWL4030_MODULE_LAST )) { -pr_err ("Invalid module Number\n" ); +pr_err ("%s: invalid module number %d\n" ,DRIVER_NAME , mod_no);return -EPERM ; } sid = twl4030_map[mod_no].sid; twl = &twl4030_modules[sid]; -if (unlikely (twl->inuse !=TWL_CLIENT_USED )) { -pr_err ("I2C Client[%d] is not initialized[%d]\n" , - sid, __LINE__); +if (unlikely (!twl->inuse)) { +pr_err ("%s: client %d is not initialized\n" ,DRIVER_NAME , sid);return -EPERM ; }mutex_lock (&twl->xfer_lock);
@@ -448,7 +417,7 @@ int twl4030_i2c_write(u8 mod_no, u8 *val msg->buf = value;/* over write the first byte of buffer with the register address */ *value = twl4030_map[mod_no].base + reg; - ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,1 ); + ret =i2c_transfer (twl->client->adapter, twl->xfer_msg,1 );mutex_unlock (&twl->xfer_lock);/* i2cTransfer returns num messages.translate it pls.. */
@@ -476,15 +445,14 @@ int twl4030_i2c_read(u8 mod_no, u8 *valustruct i2c_msg *msg;if (unlikely (mod_no >TWL4030_MODULE_LAST )) { -pr_err ("Invalid module Number\n" ); +pr_err ("%s: invalid module number %d\n" ,DRIVER_NAME , mod_no);return -EPERM ; } sid = twl4030_map[mod_no].sid; twl = &twl4030_modules[sid]; -if (unlikely (twl->inuse !=TWL_CLIENT_USED )) { -pr_err ("I2C Client[%d] is not initialized[%d]\n" , sid, - __LINE__); +if (unlikely (!twl->inuse)) { +pr_err ("%s: client %d is not initialized\n" ,DRIVER_NAME , sid);return -EPERM ; }mutex_lock (&twl->xfer_lock);
@@ -501,7 +469,7 @@ int twl4030_i2c_read(u8 mod_no, u8 *valu msg->flags =I2C_M_RD ;/* Read the register value */ msg->len = num_bytes;/* only n bytes */ msg->buf = value; - ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,2 ); + ret =i2c_transfer (twl->client->adapter, twl->xfer_msg,2 );mutex_unlock (&twl->xfer_lock);/* i2cTransfer returns num messages.translate it pls.. */
@@ -608,6 +576,8 @@ static void do_twl4030_module_irq(unsign " be masked!\n", irq); } +static unsigned twl4030_irq_base; +/* * twl4030_irq_thread() runs as a kernel thread. It queries the twl4030 * interrupt controller to see which modules are generating interrupt requests
@@ -644,7 +614,7 @@ static int twl4030_irq_thread(void *datacontinue ; } -for (module_irq =TWL4030_IRQ_BASE ;0 != pih_isr; +for (module_irq = twl4030_irq_base;0 != pih_isr; pih_isr >>=1 , module_irq++) {if (pih_isr &0x1 ) {irq_desc_t *d = irq_desc + module_irq;
@@ -693,78 +663,17 @@ static void do_twl4030_irq(unsigned int } } -/* attach a client to the adapter */ -static int __init twl4030_detect_client (struct i2c_adapter *adapter, -unsigned char sid) -{ -int err =0 ; -struct twl4030_client *twl; - -if (unlikely (sid >=TWL4030_NUM_SLAVES )) { -pr_err ("sid[%d] > MOD_LAST[%d]\n" , sid,TWL4030_NUM_SLAVES ); -return -EPERM ; - } - -/* Check basic functionality */ - err =i2c_check_functionality (adapter, -I2C_FUNC_SMBUS_WORD_DATA - |I2C_FUNC_SMBUS_WRITE_BYTE ); -if (!err) { -pr_err ("SlaveID=%d functionality check failed\n" , sid); -return err; - } - twl = &twl4030_modules[sid]; -if (unlikely (twl->inuse)) { -pr_err ("Client %s is already in use\n" , twl->client_name); -return -EPERM ; - } - -memset (&twl->client,0 ,sizeof (struct i2c_client )); - - twl->client.addr = twl->address; - twl->client.adapter = adapter; - twl->client.driver = &twl4030_driver; - -memcpy (&twl->client.name, twl->client_name, -sizeof (TWL_CLIENT_STRING ) +1 ); - -pr_info ("TWL4030: TRY attach Slave %s on Adapter %s [%x]\n" , - twl->client_name, adapter->name, err); - - err =i2c_attach_client (&twl->client); -if (err) { -pr_err ("Couldn't attach Slave %s on Adapter" -"%s [%x]\n" , twl->client_name, adapter->name, err); - }else { - twl->inuse =TWL_CLIENT_USED ; -mutex_init (&twl->xfer_lock); - } - -return err; -} - -static int add_children (void ) +static int add_children (struct twl4030_platform_data *pdata) { -static bool children; -struct platform_device *pdev =NULL ;struct twl4030_client *twl =NULL ;int status =0 ; -/* FIXME this doesn't yet set up platform_data for anything; -* it can't be available until this becomes a "new style" -* I2C driver. Similarly, a new style driver will know it -* didn't already initialize its children. -*/ - -if (children) -return 0 ; -#ifdef CONFIG_RTC_DRV_TWL4030 pdev =platform_device_alloc ("twl4030_rtc" ,-1 );if (pdev) { twl = &twl4030_modules[TWL4030_SLAVENUM_NUM3 ]; - pdev->dev.parent = &twl->client.dev; + pdev->dev.parent = &twl->client->dev;device_init_wakeup (&pdev->dev,1 );/*
@@ -788,66 +697,9 @@ static int add_children(void) status = -ENOMEM ;#endif - children = true;return status; } -/* adapter callback */ -static int __init twl4030_attach_adapter (struct i2c_adapter *adapter) -{ -int i; -int ret =0 ; -static int twl_i2c_adapter =1 ; - -for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { -/* Check if I need to hook on to this adapter or not */ -if (twl4030_modules[i].adapter_index == twl_i2c_adapter) { - ret =twl4030_detect_client (adapter, i); -if (ret) - goto free_client; - } - } - twl_i2c_adapter++; - -add_children (); - -/* -* Check if the PIH module is initialized, if yes, then init -* the T2 Interrupt subsystem -*/ -if ((twl4030_modules[twl4030_map[TWL4030_MODULE_PIH ].sid].inuse == -TWL_CLIENT_USED ) && (twl_irq_used !=USED )) { -twl_init_irq (); - twl_irq_used =USED ; - } -return 0 ; - -free_client: -pr_err ("TWL_CLIENT(Idx=%d] registration failed[0x%x]\n" , i, ret); - -/* ignore current slave..it never got registered */ - i--; -while (i >=0 ) { -/* now remove all those from the current adapter... */ -if (twl4030_modules[i].adapter_index == twl_i2c_adapter) - (void )twl4030_detach_client (&twl4030_modules[i].client); - i--; - } -return ret; -} - -/* adapter's callback */ -static int twl4030_detach_client (struct i2c_client *client) -{ -int err; - err =i2c_detach_client (client); -if (err) { -pr_err ("Client detach failed\n" ); -return err; - } -return 0 ; -} -static struct task_struct *__init start_twl4030_irq_thread (int irq) {struct task_struct *thread;
@@ -1005,12 +857,11 @@ static void __init twl4030_mask_clear_in } -static void twl_init_irq (void ) +static void twl_init_irq (int irq_num,unsigned irq_base,unsigned irq_end) {int i;int res =0 ;char *msg ="Unable to register interrupt subsystem" ; -unsigned int irq_num;/* * Mask and clear all TWL4030 interrupts since initially we do
@@ -1019,15 +870,15 @@ static void twl_init_irq(void)twl4030_mask_clear_intrs (twl4030_mod_regs,ARRAY_SIZE (twl4030_mod_regs)); + twl4030_irq_base = irq_base; +/* install an irq handler for each of the PIH modules */ -for (i =TWL4030_IRQ_BASE ; i <TWL4030_IRQ_END ; i++) { +for (i = irq_base; i < irq_end; i++) {set_irq_chip (i, &twl4030_irq_chip);set_irq_handler (i, do_twl4030_module_irq);set_irq_flags (i,IRQF_VALID ); } - irq_num = (cpu_is_omap2430 ()) ?INT_24XX_SYS_NIRQ :INT_34XX_SYS_NIRQ ; -/* install an irq handler to demultiplex the TWL4030 interrupt */ set_irq_data (irq_num,start_twl4030_irq_thread (irq_num));set_irq_type (irq_num,IRQ_TYPE_EDGE_FALLING );
@@ -1035,24 +886,133 @@ static void twl_init_irq(void) res =power_companion_init ();if (res <0 ) -pr_err ("%s[%d][%d]\n" , msg, res, __LINE__); +pr_err ("%s: %s[%d]\n" ,DRIVER_NAME , msg, res); +} + +/*----------------------------------------------------------------------*/ + +static int twl4030_remove (struct i2c_client *client) +{ +unsigned i; + +/* FIXME undo twl_init_irq() */ +if (twl4030_irq_base) { +dev_err (&client->dev,"can't yet clean up IRQs?\n" ); +return -ENOSYS ; + } + +for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { +struct twl4030_client *twl = &twl4030_modules[i]; + +if (twl->client && twl->client != client) +i2c_unregister_device (twl->client); + twl4030_modules[i].client =NULL ; + twl4030_modules[i].inuse = false; + } +return 0 ; +} + +/* NOTE: this driver only handles a single twl4030/tps659x0 chip */ +static int +twl4030_probe (struct i2c_client *client,const struct i2c_device_id *id) +{ +int status; +unsigned i; +struct twl4030_platform_data *pdata = client->dev.platform_data; + +if (!pdata) { +dev_dbg (&client->dev,"no platform data?\n" ); +return -EINVAL ; + } + +if (i2c_check_functionality (client->adapter,I2C_FUNC_I2C ) ==0 ) { +dev_dbg (&client->dev,"can't talk I2C?\n" ); +return -EIO ; + } + +for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { +if (twl4030_modules[i].inuse || twl4030_irq_base) { +dev_dbg (&client->dev,"driver is already in use\n" ); +return -EBUSY ; + } + } + +for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { +struct twl4030_client *twl = &twl4030_modules[i]; + +if (i ==0 ) + twl->client = client; +else { + twl->client =i2c_new_dummy (client->adapter, + twl->address); +if (!twl->client) { +dev_err (&twl->client->dev, +"can't attach client %d\n" , i); + status = -ENOMEM ; + goto fail; + } +strlcpy (twl->client->name, id->name, +sizeof (twl->client->name)); + } + twl->inuse = true; +mutex_init (&twl->xfer_lock); + } + + status =add_children (pdata); +if (status <0 ) + goto fail; + +/* +* Check if the PIH module is initialized, if yes, then init +* the T2 Interrupt subsystem +*/ +if (twl4030_modules[twl4030_map[TWL4030_MODULE_PIH ].sid].inuse + && twl4030_irq_base ==0 + && client->irq + && pdata->irq_base + && pdata->irq_end > pdata->irq_base) +twl_init_irq (client->irq, pdata->irq_base, pdata->irq_end); + +dev_info (&client->dev,"chaining %d irqs\n" , + twl4030_irq_base + ? (pdata->irq_end - pdata->irq_base) + :0 ); +return 0 ; + +fail: +twl4030_remove (client); +return status; } +static const struct i2c_device_id twl4030_ids[] = { + {"twl4030" ,0 },/* "Triton 2" */ + {"tps65950" ,0 },/* catalog version of twl4030 */ + {"tps65930" ,0 },/* fewer LDOs and DACs; no charger */ + {"tps65920" ,0 },/* fewer LDOs; no codec or charger */ + {/* end of list */ }, +}; +MODULE_DEVICE_TABLE (i2c, twl4030_ids); + +/* One Client Driver , 4 Clients */ +static struct i2c_driver twl4030_driver = { + .driver.name =DRIVER_NAME , + .id_table = twl4030_ids, + .probe = twl4030_probe, + .remove = twl4030_remove, +}; +static int __init twl4030_init (void ) {return i2c_add_driver (&twl4030_driver); } +subsys_initcall (twl4030_init); static void __exit twl4030_exit(void) {i2c_del_driver (&twl4030_driver); - twl_irq_used =FREE ; } - -subsys_initcall (twl4030_init);module_exit (twl4030_exit); -MODULE_ALIAS ("i2c:" DRIVER_NAME );MODULE_AUTHOR ("Texas Instruments, Inc." );MODULE_DESCRIPTION ("I2C Core interface for TWL4030" );MODULE_LICENSE ("GPL" );
include/linux/i2c/twl4030.h +11 -0
@@ -52,6 +52,17 @@#define TWL4030_MODULE_RTC 0x14#define TWL4030_MODULE_SECURED_REG 0x15 +struct twl4030_platform_data { +unsigned irq_base, irq_end; + +/* REVISIT more to come ... _nothing_ should be hard-wired */ +}; + +/* +* FIXME completely stop using TWL4030_IRQ_BASE ... instead, pass the +* IRQ data to subsidiary devices using platform device resources. +*/ +/* IRQ information-need base */ #include <mach/irqs.h> /* TWL4030 interrupts */
Quoted 13 lines · David Brownell
More updates preparing for upstream merge of twl4030 driver:
Basic fixes
- twl4030-core becomes a new-style I2C driver
- declare and useplatform_datastructure for that core
- stop hard-wiring the irq numbers
- check functionality that's really used: I2C, not SMBus
Cleanup:
- remove needless "client string"
- remove some fake "bool" types
- include catalog part numbers (TPS659{5,3,2}0)
- diagnostics should identify the driver!
Quoted 7 lines
To use this, all boards with these chips will need to declare this chip when they declare their active I2C busses (done in a separate patch).
NOTE: the TWL4030_IRQ_* symbols still need to vanish, along with other global resource assignments associated with these chips.
Signed-off-by David Brownell <[email protected]>
uuuu, great :-)
Thanks a lot Dave, we're getting there :-D
Hopefully twl can make its way to mainline before 2.6.29 ;-)
Quoted 513 lines
--- drivers/i2c/chips/twl4030-core.c | 308 ++++++++++++++++--------------------- include/linux/i2c/twl4030.h | 11 + 2 files changed, 145 insertions(+), 174 deletions(-)drivers/i2c/chips/twl4030-core.c +134
-174@@ -1,5 +1,5 @@/* -* twl4030_core.c - driver for TWL4030 PM and audio CODEC device +* twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices * * Copyright (C) 2005-2006 Texas Instruments, Inc. * @@ -56,14 +56,6 @@#define DRIVER_NAME "twl4030" -/* Macro Definitions */ -#define TWL_CLIENT_STRING "TWL4030-ID" -#define TWL_CLIENT_USED 1 -#define TWL_CLIENT_FREE 0 - -/* IRQ Flags */ -#define FREE 0 -#define USED 1/* Primary Interrupt Handler on TWL4030 Registers */ @@ -293,26 +285,18 @@ static const struct twl4030_mod_iregs __/* Helper functions */ -static int -twl4030_detect_client (struct i2c_adapter *adapter,unsigned char sid); -static int twl4030_attach_adapter (struct i2c_adapter *adapter); -static int twl4030_detach_client (struct i2c_client *client);static void do_twl4030_irq (unsigned int irq,irq_desc_t *desc); -static void twl_init_irq (void ); -/* Data Structures */ /* To have info on T2 IRQ substem activated or not */ -static unsigned char twl_irq_used =FREE ;static struct completion irq_event;/* Structure to define on TWL4030 Slave ID */ struct twl4030_client { -struct i2c_client client; -const char client_name[sizeof (TWL_CLIENT_STRING ) +1 ]; +struct i2c_client *client;const unsigned char address;const char adapter_index; -unsigned char inuse; +bool inuse;/* max numb of i2c_msg required is for read =2 */ struct i2c_msg xfer_msg[2 ];@@ -356,36 +340,22 @@ static struct twl4030mapping twl4030_mapstatic struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES ] = { { .address =TWL4030_SLAVEID_ID0 , - .client_name =TWL_CLIENT_STRING "0" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, { .address =TWL4030_SLAVEID_ID1 , - .client_name =TWL_CLIENT_STRING "1" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, { .address =TWL4030_SLAVEID_ID2 , - .client_name =TWL_CLIENT_STRING "2" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, { .address =TWL4030_SLAVEID_ID3 , - .client_name =TWL_CLIENT_STRING "3" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, }; -/* One Client Driver , 4 Clients */ -static struct i2c_driver twl4030_driver = { - .driver = { - .name =DRIVER_NAME , - .owner =THIS_MODULE , - }, - .attach_adapter = twl4030_attach_adapter, - .detach_client = twl4030_detach_client, -}; -/* * TWL4030 doesn't have PIH mask, hence dummy function for mask * and unmask. @@ -425,15 +395,14 @@ int twl4030_i2c_write(u8 mod_no, u8 *valstruct i2c_msg *msg;if (unlikely (mod_no >TWL4030_MODULE_LAST )) { -pr_err ("Invalid module Number\n" ); +pr_err ("%s: invalid module number %d\n" ,DRIVER_NAME , mod_no);return -EPERM ; } sid = twl4030_map[mod_no].sid; twl = &twl4030_modules[sid]; -if (unlikely (twl->inuse !=TWL_CLIENT_USED )) { -pr_err ("I2C Client[%d] is not initialized[%d]\n" , - sid, __LINE__); +if (unlikely (!twl->inuse)) { +pr_err ("%s: client %d is not initialized\n" ,DRIVER_NAME , sid);return -EPERM ; }mutex_lock (&twl->xfer_lock);@@ -448,7 +417,7 @@ int twl4030_i2c_write(u8 mod_no, u8 *val msg->buf = value;/* over write the first byte of buffer with the register address */ *value = twl4030_map[mod_no].base + reg; - ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,1 ); + ret =i2c_transfer (twl->client->adapter, twl->xfer_msg,1 );mutex_unlock (&twl->xfer_lock);/* i2cTransfer returns num messages.translate it pls.. */ @@ -476,15 +445,14 @@ int twl4030_i2c_read(u8 mod_no, u8 *valustruct i2c_msg *msg;if (unlikely (mod_no >TWL4030_MODULE_LAST )) { -pr_err ("Invalid module Number\n" ); +pr_err ("%s: invalid module number %d\n" ,DRIVER_NAME , mod_no);return -EPERM ; } sid = twl4030_map[mod_no].sid; twl = &twl4030_modules[sid]; -if (unlikely (twl->inuse !=TWL_CLIENT_USED )) { -pr_err ("I2C Client[%d] is not initialized[%d]\n" , sid, - __LINE__); +if (unlikely (!twl->inuse)) { +pr_err ("%s: client %d is not initialized\n" ,DRIVER_NAME , sid);return -EPERM ; }mutex_lock (&twl->xfer_lock);@@ -501,7 +469,7 @@ int twl4030_i2c_read(u8 mod_no, u8 *valu msg->flags =I2C_M_RD ;/* Read the register value */ msg->len = num_bytes;/* only n bytes */ msg->buf = value; - ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,2 ); + ret =i2c_transfer (twl->client->adapter, twl->xfer_msg,2 );mutex_unlock (&twl->xfer_lock);/* i2cTransfer returns num messages.translate it pls.. */ @@ -608,6 +576,8 @@ static void do_twl4030_module_irq(unsign " be masked!\n", irq); } +static unsigned twl4030_irq_base; +/* * twl4030_irq_thread() runs as a kernel thread. It queries the twl4030 * interrupt controller to see which modules are generating interrupt requests @@ -644,7 +614,7 @@ static int twl4030_irq_thread(void *datacontinue ; } -for (module_irq =TWL4030_IRQ_BASE ;0 != pih_isr; +for (module_irq = twl4030_irq_base;0 != pih_isr; pih_isr >>=1 , module_irq++) {if (pih_isr &0x1 ) {irq_desc_t *d = irq_desc + module_irq;@@ -693,78 +663,17 @@ static void do_twl4030_irq(unsigned int } } -/* attach a client to the adapter */ -static int __init twl4030_detect_client (struct i2c_adapter *adapter, -unsigned char sid) -{ -int err =0 ; -struct twl4030_client *twl; - -if (unlikely (sid >=TWL4030_NUM_SLAVES )) { -pr_err ("sid[%d] > MOD_LAST[%d]\n" , sid,TWL4030_NUM_SLAVES ); -return -EPERM ; - } - -/* Check basic functionality */ - err =i2c_check_functionality (adapter, -I2C_FUNC_SMBUS_WORD_DATA - |I2C_FUNC_SMBUS_WRITE_BYTE ); -if (!err) { -pr_err ("SlaveID=%d functionality check failed\n" , sid); -return err; - } - twl = &twl4030_modules[sid]; -if (unlikely (twl->inuse)) { -pr_err ("Client %s is already in use\n" , twl->client_name); -return -EPERM ; - } - -memset (&twl->client,0 ,sizeof (struct i2c_client )); - - twl->client.addr = twl->address; - twl->client.adapter = adapter; - twl->client.driver = &twl4030_driver; - -memcpy (&twl->client.name, twl->client_name, -sizeof (TWL_CLIENT_STRING ) +1 ); - -pr_info ("TWL4030: TRY attach Slave %s on Adapter %s [%x]\n" , - twl->client_name, adapter->name, err); - - err =i2c_attach_client (&twl->client); -if (err) { -pr_err ("Couldn't attach Slave %s on Adapter" -"%s [%x]\n" , twl->client_name, adapter->name, err); - }else { - twl->inuse =TWL_CLIENT_USED ; -mutex_init (&twl->xfer_lock); - } - -return err; -} - -static int add_children (void ) +static int add_children (struct twl4030_platform_data *pdata) { -static bool children; -struct platform_device *pdev =NULL ;struct twl4030_client *twl =NULL ;int status =0 ; -/* FIXME this doesn't yet set up platform_data for anything; -* it can't be available until this becomes a "new style" -* I2C driver. Similarly, a new style driver will know it -* didn't already initialize its children. -*/ - -if (children) -return 0 ; -#ifdef CONFIG_RTC_DRV_TWL4030 pdev =platform_device_alloc ("twl4030_rtc" ,-1 );if (pdev) { twl = &twl4030_modules[TWL4030_SLAVENUM_NUM3 ]; - pdev->dev.parent = &twl->client.dev; + pdev->dev.parent = &twl->client->dev;device_init_wakeup (&pdev->dev,1 );/* @@ -788,66 +697,9 @@ static int add_children(void) status = -ENOMEM ;#endif - children = true;return status; } -/* adapter callback */ -static int __init twl4030_attach_adapter (struct i2c_adapter *adapter) -{ -int i; -int ret =0 ; -static int twl_i2c_adapter =1 ; - -for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { -/* Check if I need to hook on to this adapter or not */ -if (twl4030_modules[i].adapter_index == twl_i2c_adapter) { - ret =twl4030_detect_client (adapter, i); -if (ret) - goto free_client; - } - } - twl_i2c_adapter++; - -add_children (); - -/* -* Check if the PIH module is initialized, if yes, then init -* the T2 Interrupt subsystem -*/ -if ((twl4030_modules[twl4030_map[TWL4030_MODULE_PIH ].sid].inuse == -TWL_CLIENT_USED ) && (twl_irq_used !=USED )) { -twl_init_irq (); - twl_irq_used =USED ; - } -return 0 ; - -free_client: -pr_err ("TWL_CLIENT(Idx=%d] registration failed[0x%x]\n" , i, ret); - -/* ignore current slave..it never got registered */ - i--; -while (i >=0 ) { -/* now remove all those from the current adapter... */ -if (twl4030_modules[i].adapter_index == twl_i2c_adapter) - (void )twl4030_detach_client (&twl4030_modules[i].client); - i--; - } -return ret; -} - -/* adapter's callback */ -static int twl4030_detach_client (struct i2c_client *client) -{ -int err; - err =i2c_detach_client (client); -if (err) { -pr_err ("Client detach failed\n" ); -return err; - } -return 0 ; -} -static struct task_struct *__init start_twl4030_irq_thread (int irq) {struct task_struct *thread;@@ -1005,12 +857,11 @@ static void __init twl4030_mask_clear_in } -static void twl_init_irq (void ) +static void twl_init_irq (int irq_num,unsigned irq_base,unsigned irq_end) {int i;int res =0 ;char *msg ="Unable to register interrupt subsystem" ; -unsigned int irq_num;/* * Mask and clear all TWL4030 interrupts since initially we do @@ -1019,15 +870,15 @@ static void twl_init_irq(void)twl4030_mask_clear_intrs (twl4030_mod_regs,ARRAY_SIZE (twl4030_mod_regs)); + twl4030_irq_base = irq_base; +/* install an irq handler for each of the PIH modules */ -for (i =TWL4030_IRQ_BASE ; i <TWL4030_IRQ_END ; i++) { +for (i = irq_base; i < irq_end; i++) {set_irq_chip (i, &twl4030_irq_chip);set_irq_handler (i, do_twl4030_module_irq);set_irq_flags (i,IRQF_VALID ); } - irq_num = (cpu_is_omap2430 ()) ?INT_24XX_SYS_NIRQ :INT_34XX_SYS_NIRQ ; -/* install an irq handler to demultiplex the TWL4030 interrupt */ set_irq_data (irq_num,start_twl4030_irq_thread (irq_num));set_irq_type (irq_num,IRQ_TYPE_EDGE_FALLING );@@ -1035,24 +886,133 @@ static void twl_init_irq(void) res =power_companion_init ();if (res <0 ) -pr_err ("%s[%d][%d]\n" , msg, res, __LINE__); +pr_err ("%s: %s[%d]\n" ,DRIVER_NAME , msg, res); +} + +/*----------------------------------------------------------------------*/ + +static int twl4030_remove (struct i2c_client *client) +{ +unsigned i; + +/* FIXME undo twl_init_irq() */ +if (twl4030_irq_base) { +dev_err (&client->dev,"can't yet clean up IRQs?\n" ); +return -ENOSYS ; + } + +for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { +struct twl4030_client *twl = &twl4030_modules[i]; + +if (twl->client && twl->client != client) +i2c_unregister_device (twl->client); + twl4030_modules[i].client =NULL ; + twl4030_modules[i].inuse = false; + } +return 0 ; +} + +/* NOTE: this driver only handles a single twl4030/tps659x0 chip */ +static int +twl4030_probe (struct i2c_client *client,const struct i2c_device_id *id) +{ +int status; +unsigned i; +struct twl4030_platform_data *pdata = client->dev.platform_data; + +if (!pdata) { +dev_dbg (&client->dev,"no platform data?\n" ); +return -EINVAL ; + } + +if (i2c_check_functionality (client->adapter,I2C_FUNC_I2C ) ==0 ) { +dev_dbg (&client->dev,"can't talk I2C?\n" ); +return -EIO ; + } + +for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { +if (twl4030_modules[i].inuse || twl4030_irq_base) { +dev_dbg (&client->dev,"driver is already in use\n" ); +return -EBUSY ; + } + } + +for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { +struct twl4030_client *twl = &twl4030_modules[i]; + +if (i ==0 ) + twl->client = client; +else { + twl->client =i2c_new_dummy (client->adapter, + twl->address); +if (!twl->client) { +dev_err (&twl->client->dev, +"can't attach client %d\n" , i); + status = -ENOMEM ; + goto fail; + } +strlcpy (twl->client->name, id->name, +sizeof (twl->client->name)); + } + twl->inuse = true; +mutex_init (&twl->xfer_lock); + } + + status =add_children (pdata); +if (status <0 ) + goto fail; + +/* +* Check if the PIH module is initialized, if yes, then init +* the T2 Interrupt subsystem +*/ +if (twl4030_modules[twl4030_map[TWL4030_MODULE_PIH ].sid].inuse + && twl4030_irq_base ==0 + && client->irq + && pdata->irq_base + && pdata->irq_end > pdata->irq_base) +twl_init_irq (client->irq, pdata->irq_base, pdata->irq_end); + +dev_info (&client->dev,"chaining %d irqs\n" , + twl4030_irq_base + ? (pdata->irq_end - pdata->irq_base) + :0 ); +return 0 ; + +fail: +twl4030_remove (client); +return status; } +static const struct i2c_device_id twl4030_ids[] = { + {"twl4030" ,0 },/* "Triton 2" */ + {"tps65950" ,0 },/* catalog version of twl4030 */ + {"tps65930" ,0 },/* fewer LDOs and DACs; no charger */ + {"tps65920" ,0 },/* fewer LDOs; no codec or charger */ + {/* end of list */ }, +}; +MODULE_DEVICE_TABLE (i2c, twl4030_ids); + +/* One Client Driver , 4 Clients */ +static struct i2c_driver twl4030_driver = { + .driver.name =DRIVER_NAME , + .id_table = twl4030_ids, + .probe = twl4030_probe, + .remove = twl4030_remove, +}; +static int __init twl4030_init (void ) {return i2c_add_driver (&twl4030_driver); } +subsys_initcall (twl4030_init); static void __exit twl4030_exit(void) {i2c_del_driver (&twl4030_driver); - twl_irq_used =FREE ; } - -subsys_initcall (twl4030_init);module_exit (twl4030_exit); -MODULE_ALIAS ("i2c:" DRIVER_NAME );MODULE_AUTHOR ("Texas Instruments, Inc." );MODULE_DESCRIPTION ("I2C Core interface for TWL4030" );MODULE_LICENSE ("GPL" );include/linux/i2c/twl4030.h +11
-1@@ -52,6 +52,17 @@#define TWL4030_MODULE_RTC 0x14#define TWL4030_MODULE_SECURED_REG 0x15 +struct twl4030_platform_data { +unsigned irq_base, irq_end; + +/* REVISIT more to come ... _nothing_ should be hard-wired */ +}; + +/* +* FIXME completely stop using TWL4030_IRQ_BASE ... instead, pass the +* IRQ data to subsidiary devices using platform device resources. +*/ +/* IRQ information-need base */ #include <mach/irqs.h> /* TWL4030 interrupts */ --To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 1 line
balbi
Quoted 20 lines · Felipe Balbi
Quoted 19 lines · David Brownell
More updates preparing for upstream merge of twl4030 driver:
Basic fixes
- twl4030-core becomes a new-style I2C driver
- declare and useplatform_datastructure for that core
- stop hard-wiring the irq numbers
- check functionality that's really used: I2C, not SMBus
Cleanup:
- remove needless "client string"
- remove some fake "bool" types
- include catalog part numbers (TPS659{5,3,2}0)
- diagnostics should identify the driver!To use this, all boards with these chips will need to declare this chip when they declare their active I2C busses (done in a separate patch).
NOTE: the TWL4030_IRQ_* symbols still need to vanish, along with other global resource assignments associated with these chips.
Quoted 7 lines
Quoted 1 line
Signed-off-by David Brownell <[email protected]>uuuu, great :-)
Thanks a lot Dave, we're getting there :-D
Hopefully twl can make its way to mainline before 2.6.29 ;-)
Great, pushing.
Tony
Quoted 521 lines
Quoted 514 lines
--- drivers/i2c/chips/twl4030-core.c | 308 ++++++++++++++++--------------------- include/linux/i2c/twl4030.h | 11 + 2 files changed, 145 insertions(+), 174 deletions(-)drivers/i2c/chips/twl4030-core.c +134
-174@@ -1,5 +1,5 @@/* -* twl4030_core.c - driver for TWL4030 PM and audio CODEC device +* twl4030_core.c - driver for TWL4030/TPS659x0 PM and audio CODEC devices * * Copyright (C) 2005-2006 Texas Instruments, Inc. * @@ -56,14 +56,6 @@#define DRIVER_NAME "twl4030" -/* Macro Definitions */ -#define TWL_CLIENT_STRING "TWL4030-ID" -#define TWL_CLIENT_USED 1 -#define TWL_CLIENT_FREE 0 - -/* IRQ Flags */ -#define FREE 0 -#define USED 1/* Primary Interrupt Handler on TWL4030 Registers */ @@ -293,26 +285,18 @@ static const struct twl4030_mod_iregs __/* Helper functions */ -static int -twl4030_detect_client (struct i2c_adapter *adapter,unsigned char sid); -static int twl4030_attach_adapter (struct i2c_adapter *adapter); -static int twl4030_detach_client (struct i2c_client *client);static void do_twl4030_irq (unsigned int irq,irq_desc_t *desc); -static void twl_init_irq (void ); -/* Data Structures */ /* To have info on T2 IRQ substem activated or not */ -static unsigned char twl_irq_used =FREE ;static struct completion irq_event;/* Structure to define on TWL4030 Slave ID */ struct twl4030_client { -struct i2c_client client; -const char client_name[sizeof (TWL_CLIENT_STRING ) +1 ]; +struct i2c_client *client;const unsigned char address;const char adapter_index; -unsigned char inuse; +bool inuse;/* max numb of i2c_msg required is for read =2 */ struct i2c_msg xfer_msg[2 ];@@ -356,36 +340,22 @@ static struct twl4030mapping twl4030_mapstatic struct twl4030_client twl4030_modules[TWL4030_NUM_SLAVES ] = { { .address =TWL4030_SLAVEID_ID0 , - .client_name =TWL_CLIENT_STRING "0" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, { .address =TWL4030_SLAVEID_ID1 , - .client_name =TWL_CLIENT_STRING "1" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, { .address =TWL4030_SLAVEID_ID2 , - .client_name =TWL_CLIENT_STRING "2" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, { .address =TWL4030_SLAVEID_ID3 , - .client_name =TWL_CLIENT_STRING "3" , .adapter_index =CONFIG_I2C_TWL4030_ID , }, }; -/* One Client Driver , 4 Clients */ -static struct i2c_driver twl4030_driver = { - .driver = { - .name =DRIVER_NAME , - .owner =THIS_MODULE , - }, - .attach_adapter = twl4030_attach_adapter, - .detach_client = twl4030_detach_client, -}; -/* * TWL4030 doesn't have PIH mask, hence dummy function for mask * and unmask. @@ -425,15 +395,14 @@ int twl4030_i2c_write(u8 mod_no, u8 *valstruct i2c_msg *msg;if (unlikely (mod_no >TWL4030_MODULE_LAST )) { -pr_err ("Invalid module Number\n" ); +pr_err ("%s: invalid module number %d\n" ,DRIVER_NAME , mod_no);return -EPERM ; } sid = twl4030_map[mod_no].sid; twl = &twl4030_modules[sid]; -if (unlikely (twl->inuse !=TWL_CLIENT_USED )) { -pr_err ("I2C Client[%d] is not initialized[%d]\n" , - sid, __LINE__); +if (unlikely (!twl->inuse)) { +pr_err ("%s: client %d is not initialized\n" ,DRIVER_NAME , sid);return -EPERM ; }mutex_lock (&twl->xfer_lock);@@ -448,7 +417,7 @@ int twl4030_i2c_write(u8 mod_no, u8 *val msg->buf = value;/* over write the first byte of buffer with the register address */ *value = twl4030_map[mod_no].base + reg; - ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,1 ); + ret =i2c_transfer (twl->client->adapter, twl->xfer_msg,1 );mutex_unlock (&twl->xfer_lock);/* i2cTransfer returns num messages.translate it pls.. */ @@ -476,15 +445,14 @@ int twl4030_i2c_read(u8 mod_no, u8 *valustruct i2c_msg *msg;if (unlikely (mod_no >TWL4030_MODULE_LAST )) { -pr_err ("Invalid module Number\n" ); +pr_err ("%s: invalid module number %d\n" ,DRIVER_NAME , mod_no);return -EPERM ; } sid = twl4030_map[mod_no].sid; twl = &twl4030_modules[sid]; -if (unlikely (twl->inuse !=TWL_CLIENT_USED )) { -pr_err ("I2C Client[%d] is not initialized[%d]\n" , sid, - __LINE__); +if (unlikely (!twl->inuse)) { +pr_err ("%s: client %d is not initialized\n" ,DRIVER_NAME , sid);return -EPERM ; }mutex_lock (&twl->xfer_lock);@@ -501,7 +469,7 @@ int twl4030_i2c_read(u8 mod_no, u8 *valu msg->flags =I2C_M_RD ;/* Read the register value */ msg->len = num_bytes;/* only n bytes */ msg->buf = value; - ret =i2c_transfer (twl->client.adapter, twl->xfer_msg,2 ); + ret =i2c_transfer (twl->client->adapter, twl->xfer_msg,2 );mutex_unlock (&twl->xfer_lock);/* i2cTransfer returns num messages.translate it pls.. */ @@ -608,6 +576,8 @@ static void do_twl4030_module_irq(unsign " be masked!\n", irq); } +static unsigned twl4030_irq_base; +/* * twl4030_irq_thread() runs as a kernel thread. It queries the twl4030 * interrupt controller to see which modules are generating interrupt requests @@ -644,7 +614,7 @@ static int twl4030_irq_thread(void *datacontinue ; } -for (module_irq =TWL4030_IRQ_BASE ;0 != pih_isr; +for (module_irq = twl4030_irq_base;0 != pih_isr; pih_isr >>=1 , module_irq++) {if (pih_isr &0x1 ) {irq_desc_t *d = irq_desc + module_irq;@@ -693,78 +663,17 @@ static void do_twl4030_irq(unsigned int } } -/* attach a client to the adapter */ -static int __init twl4030_detect_client (struct i2c_adapter *adapter, -unsigned char sid) -{ -int err =0 ; -struct twl4030_client *twl; - -if (unlikely (sid >=TWL4030_NUM_SLAVES )) { -pr_err ("sid[%d] > MOD_LAST[%d]\n" , sid,TWL4030_NUM_SLAVES ); -return -EPERM ; - } - -/* Check basic functionality */ - err =i2c_check_functionality (adapter, -I2C_FUNC_SMBUS_WORD_DATA - |I2C_FUNC_SMBUS_WRITE_BYTE ); -if (!err) { -pr_err ("SlaveID=%d functionality check failed\n" , sid); -return err; - } - twl = &twl4030_modules[sid]; -if (unlikely (twl->inuse)) { -pr_err ("Client %s is already in use\n" , twl->client_name); -return -EPERM ; - } - -memset (&twl->client,0 ,sizeof (struct i2c_client )); - - twl->client.addr = twl->address; - twl->client.adapter = adapter; - twl->client.driver = &twl4030_driver; - -memcpy (&twl->client.name, twl->client_name, -sizeof (TWL_CLIENT_STRING ) +1 ); - -pr_info ("TWL4030: TRY attach Slave %s on Adapter %s [%x]\n" , - twl->client_name, adapter->name, err); - - err =i2c_attach_client (&twl->client); -if (err) { -pr_err ("Couldn't attach Slave %s on Adapter" -"%s [%x]\n" , twl->client_name, adapter->name, err); - }else { - twl->inuse =TWL_CLIENT_USED ; -mutex_init (&twl->xfer_lock); - } - -return err; -} - -static int add_children (void ) +static int add_children (struct twl4030_platform_data *pdata) { -static bool children; -struct platform_device *pdev =NULL ;struct twl4030_client *twl =NULL ;int status =0 ; -/* FIXME this doesn't yet set up platform_data for anything; -* it can't be available until this becomes a "new style" -* I2C driver. Similarly, a new style driver will know it -* didn't already initialize its children. -*/ - -if (children) -return 0 ; -#ifdef CONFIG_RTC_DRV_TWL4030 pdev =platform_device_alloc ("twl4030_rtc" ,-1 );if (pdev) { twl = &twl4030_modules[TWL4030_SLAVENUM_NUM3 ]; - pdev->dev.parent = &twl->client.dev; + pdev->dev.parent = &twl->client->dev;device_init_wakeup (&pdev->dev,1 );/* @@ -788,66 +697,9 @@ static int add_children(void) status = -ENOMEM ;#endif - children = true;return status; } -/* adapter callback */ -static int __init twl4030_attach_adapter (struct i2c_adapter *adapter) -{ -int i; -int ret =0 ; -static int twl_i2c_adapter =1 ; - -for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { -/* Check if I need to hook on to this adapter or not */ -if (twl4030_modules[i].adapter_index == twl_i2c_adapter) { - ret =twl4030_detect_client (adapter, i); -if (ret) - goto free_client; - } - } - twl_i2c_adapter++; - -add_children (); - -/* -* Check if the PIH module is initialized, if yes, then init -* the T2 Interrupt subsystem -*/ -if ((twl4030_modules[twl4030_map[TWL4030_MODULE_PIH ].sid].inuse == -TWL_CLIENT_USED ) && (twl_irq_used !=USED )) { -twl_init_irq (); - twl_irq_used =USED ; - } -return 0 ; - -free_client: -pr_err ("TWL_CLIENT(Idx=%d] registration failed[0x%x]\n" , i, ret); - -/* ignore current slave..it never got registered */ - i--; -while (i >=0 ) { -/* now remove all those from the current adapter... */ -if (twl4030_modules[i].adapter_index == twl_i2c_adapter) - (void )twl4030_detach_client (&twl4030_modules[i].client); - i--; - } -return ret; -} - -/* adapter's callback */ -static int twl4030_detach_client (struct i2c_client *client) -{ -int err; - err =i2c_detach_client (client); -if (err) { -pr_err ("Client detach failed\n" ); -return err; - } -return 0 ; -} -static struct task_struct *__init start_twl4030_irq_thread (int irq) {struct task_struct *thread;@@ -1005,12 +857,11 @@ static void __init twl4030_mask_clear_in } -static void twl_init_irq (void ) +static void twl_init_irq (int irq_num,unsigned irq_base,unsigned irq_end) {int i;int res =0 ;char *msg ="Unable to register interrupt subsystem" ; -unsigned int irq_num;/* * Mask and clear all TWL4030 interrupts since initially we do @@ -1019,15 +870,15 @@ static void twl_init_irq(void)twl4030_mask_clear_intrs (twl4030_mod_regs,ARRAY_SIZE (twl4030_mod_regs)); + twl4030_irq_base = irq_base; +/* install an irq handler for each of the PIH modules */ -for (i =TWL4030_IRQ_BASE ; i <TWL4030_IRQ_END ; i++) { +for (i = irq_base; i < irq_end; i++) {set_irq_chip (i, &twl4030_irq_chip);set_irq_handler (i, do_twl4030_module_irq);set_irq_flags (i,IRQF_VALID ); } - irq_num = (cpu_is_omap2430 ()) ?INT_24XX_SYS_NIRQ :INT_34XX_SYS_NIRQ ; -/* install an irq handler to demultiplex the TWL4030 interrupt */ set_irq_data (irq_num,start_twl4030_irq_thread (irq_num));set_irq_type (irq_num,IRQ_TYPE_EDGE_FALLING );@@ -1035,24 +886,133 @@ static void twl_init_irq(void) res =power_companion_init ();if (res <0 ) -pr_err ("%s[%d][%d]\n" , msg, res, __LINE__); +pr_err ("%s: %s[%d]\n" ,DRIVER_NAME , msg, res); +} + +/*----------------------------------------------------------------------*/ + +static int twl4030_remove (struct i2c_client *client) +{ +unsigned i; + +/* FIXME undo twl_init_irq() */ +if (twl4030_irq_base) { +dev_err (&client->dev,"can't yet clean up IRQs?\n" ); +return -ENOSYS ; + } + +for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { +struct twl4030_client *twl = &twl4030_modules[i]; + +if (twl->client && twl->client != client) +i2c_unregister_device (twl->client); + twl4030_modules[i].client =NULL ; + twl4030_modules[i].inuse = false; + } +return 0 ; +} + +/* NOTE: this driver only handles a single twl4030/tps659x0 chip */ +static int +twl4030_probe (struct i2c_client *client,const struct i2c_device_id *id) +{ +int status; +unsigned i; +struct twl4030_platform_data *pdata = client->dev.platform_data; + +if (!pdata) { +dev_dbg (&client->dev,"no platform data?\n" ); +return -EINVAL ; + } + +if (i2c_check_functionality (client->adapter,I2C_FUNC_I2C ) ==0 ) { +dev_dbg (&client->dev,"can't talk I2C?\n" ); +return -EIO ; + } + +for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { +if (twl4030_modules[i].inuse || twl4030_irq_base) { +dev_dbg (&client->dev,"driver is already in use\n" ); +return -EBUSY ; + } + } + +for (i =0 ; i <TWL4030_NUM_SLAVES ; i++) { +struct twl4030_client *twl = &twl4030_modules[i]; + +if (i ==0 ) + twl->client = client; +else { + twl->client =i2c_new_dummy (client->adapter, + twl->address); +if (!twl->client) { +dev_err (&twl->client->dev, +"can't attach client %d\n" , i); + status = -ENOMEM ; + goto fail; + } +strlcpy (twl->client->name, id->name, +sizeof (twl->client->name)); + } + twl->inuse = true; +mutex_init (&twl->xfer_lock); + } + + status =add_children (pdata); +if (status <0 ) + goto fail; + +/* +* Check if the PIH module is initialized, if yes, then init +* the T2 Interrupt subsystem +*/ +if (twl4030_modules[twl4030_map[TWL4030_MODULE_PIH ].sid].inuse + && twl4030_irq_base ==0 + && client->irq + && pdata->irq_base + && pdata->irq_end > pdata->irq_base) +twl_init_irq (client->irq, pdata->irq_base, pdata->irq_end); + +dev_info (&client->dev,"chaining %d irqs\n" , + twl4030_irq_base + ? (pdata->irq_end - pdata->irq_base) + :0 ); +return 0 ; + +fail: +twl4030_remove (client); +return status; } +static const struct i2c_device_id twl4030_ids[] = { + {"twl4030" ,0 },/* "Triton 2" */ + {"tps65950" ,0 },/* catalog version of twl4030 */ + {"tps65930" ,0 },/* fewer LDOs and DACs; no charger */ + {"tps65920" ,0 },/* fewer LDOs; no codec or charger */ + {/* end of list */ }, +}; +MODULE_DEVICE_TABLE (i2c, twl4030_ids); + +/* One Client Driver , 4 Clients */ +static struct i2c_driver twl4030_driver = { + .driver.name =DRIVER_NAME , + .id_table = twl4030_ids, + .probe = twl4030_probe, + .remove = twl4030_remove, +}; +static int __init twl4030_init (void ) {return i2c_add_driver (&twl4030_driver); } +subsys_initcall (twl4030_init); static void __exit twl4030_exit(void) {i2c_del_driver (&twl4030_driver); - twl_irq_used =FREE ; } - -subsys_initcall (twl4030_init);module_exit (twl4030_exit); -MODULE_ALIAS ("i2c:" DRIVER_NAME );MODULE_AUTHOR ("Texas Instruments, Inc." );MODULE_DESCRIPTION ("I2C Core interface for TWL4030" );MODULE_LICENSE ("GPL" );include/linux/i2c/twl4030.h +11
-1@@ -52,6 +52,17 @@#define TWL4030_MODULE_RTC 0x14#define TWL4030_MODULE_SECURED_REG 0x15 +struct twl4030_platform_data { +unsigned irq_base, irq_end; + +/* REVISIT more to come ... _nothing_ should be hard-wired */ +}; + +/* +* FIXME completely stop using TWL4030_IRQ_BASE ... instead, pass the +* IRQ data to subsidiary devices using platform device resources. +*/ +/* IRQ information-need base */ #include <mach/irqs.h> /* TWL4030 interrupts */ --To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.htmlSignature · 5 lines
balbi -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html