#include <linux/kthread.h>
#include <linux/i2c.h>
+#include <linux/i2c/twl4030.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
-#include <asm/arch/twl4030.h>
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
-/**** Macro Definitions */
+#define DRIVER_NAME "twl4030"
+
+/* Macro Definitions */
#define TWL_CLIENT_STRING "TWL4030-ID"
#define TWL_CLIENT_USED 1
#define TWL_CLIENT_FREE 0
#define FREE 0
#define USED 1
-/** Primary Interrupt Handler on TWL4030 Registers */
+/* Primary Interrupt Handler on TWL4030 Registers */
-/**** Register Definitions */
+/* Register Definitions */
#define REG_PIH_ISR_P1 (0x1)
#define REG_PIH_ISR_P2 (0x2)
#define TWL4030_BASEADD_BACKUP 0x0014
#define TWL4030_BASEADD_INT 0x002E
#define TWL4030_BASEADD_PM_MASTER 0x0036
-#define TWL4030_BASEADD_PM_RECIEVER 0x005B
+#define TWL4030_BASEADD_PM_RECEIVER 0x005B
#define TWL4030_BASEADD_RTC 0x001C
#define TWL4030_BASEADD_SECURED_REG 0x0000
/* on I2C-1 for 2430SDP */
#define CONFIG_I2C_TWL4030_ID 1
-/**** Helper functions */
+/* Helper functions */
static int
twl4030_detect_client(struct i2c_adapter *adapter, unsigned char sid);
static int twl4030_attach_adapter(struct i2c_adapter *adapter);
static void twl_init_irq(void);
-/**** Data Structures */
+/* 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 {
{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_BACKUP },
{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_INT },
{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_MASTER },
- { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_RECIEVER },
+ { TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_PM_RECEIVER },
{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_RTC },
{ TWL4030_SLAVENUM_NUM3, TWL4030_BASEADD_SECURED_REG },
};
struct i2c_msg *msg;
if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
- printk(KERN_ERR "TWL4030: Invalid module Number\n");
+ pr_err("Invalid module Number\n");
return -EPERM;
}
sid = twl4030_map[mod_no].sid;
client = &(twl4030_modules[sid]);
if (unlikely(client->inuse != TWL_CLIENT_USED)) {
- printk(KERN_ERR
- "TWL4030: I2C Client[%d] is not initialized[%d]\n",
- sid, __LINE__);
+ pr_err("I2C Client[%d] is not initialized[%d]\n",
+ sid, __LINE__);
return -EPERM;
}
down(&(client->xfer_lock));
int sid;
struct twl4030_client *client;
struct i2c_msg *msg;
+
if (unlikely(mod_no > TWL4030_MODULE_LAST)) {
- printk(KERN_ERR "TWL4030: Invalid module Number\n");
+ pr_err("Invalid module Number\n");
return -EPERM;
}
sid = twl4030_map[mod_no].sid;
client = &(twl4030_modules[sid]);
if (unlikely(client->inuse != TWL_CLIENT_USED)) {
- printk(KERN_ERR
- "TWL4030: I2C Client[%d] is not initialized[%d]\n",
- sid, __LINE__);
+ pr_err("I2C Client[%d] is not initialized[%d]\n", sid,
+ __LINE__);
return -EPERM;
}
down(&(client->xfer_lock));
msg = &(client->xfer_msg[0]);
msg->addr = client->address;
msg->len = 1;
+ msg->flags = 0; /* Read the register value */
val = twl4030_map[mod_no].base + reg;
msg->buf = &val;
/* [MSG2] fill the data rx buffer */
*/
int twl4030_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
{
- int ret;
+
/* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
u8 temp_buffer[2] = { 0 };
/* offset 1 contains the data */
temp_buffer[1] = value;
- ret = twl4030_i2c_write(mod_no, temp_buffer, reg, 1);
- return ret;
+ return twl4030_i2c_write(mod_no, temp_buffer, reg, 1);
}
/**
*/
int twl4030_i2c_read_u8(u8 mod_no, u8 * value, u8 reg)
{
- int ret = 0;
- ret = twl4030_i2c_read(mod_no, value, reg, 1);
- return ret;
+ return twl4030_i2c_read(mod_no, value, reg, 1);
}
-/**** Helper Functions */
+/* Helper Functions */
/*
* do_twl4030_module_irq() is the desc->handle method for each of the twl4030
/*
* Earlier this was desc->triggered = 1;
*/
- desc->status = IRQ_INPROGRESS;
+ desc->status |= IRQ_LEVEL;
/*
* The desc->handle method would normally call the desc->chip->ack
static unsigned i2c_errors;
const static unsigned max_i2c_errors = 100;
+ daemonize("twl4030-irq");
+ current->flags |= PF_NOFREEZE;
+
while (!kthread_should_stop()) {
int ret;
int module_irq;
u8 pih_isr;
+ wait_for_completion_interruptible(&irq_event);
+
ret = twl4030_i2c_read_u8(TWL4030_MODULE_PIH, &pih_isr,
REG_PIH_ISR_P1);
if (ret) {
}
}
- local_irq_disable();
-
- set_current_state(TASK_INTERRUPTIBLE);
desc->chip->unmask(irq);
-
- local_irq_enable();
-
- schedule();
}
- set_current_state(TASK_RUNNING);
+
return 0;
}
static void do_twl4030_irq(unsigned int irq, irq_desc_t *desc)
{
const unsigned int cpu = smp_processor_id();
- struct task_struct *thread = (struct task_struct *)desc->chip_data;
/*
* Earlier this was desc->triggered = 1;
*/
- desc->status = IRQ_INPROGRESS;
+ desc->status |= IRQ_LEVEL;
/*
* Acknowledge, clear _AND_ disable the interrupt.
if (!desc->depth) {
kstat_cpu(cpu).irqs[irq]++;
- if (thread && thread->state != TASK_RUNNING)
- wake_up_process(thread);
+ complete(&irq_event);
}
}
{
int err = 0;
struct twl4030_client *client;
+
if (unlikely(sid >= TWL4030_NUM_SLAVES)) {
- printk(KERN_ERR "TWL4030: sid[%d] >MOD_LAST[%d]\n", sid,
- TWL4030_NUM_SLAVES);
+ pr_err("sid[%d] > MOD_LAST[%d]\n", sid, TWL4030_NUM_SLAVES);
return -EPERM;
}
/* Check basic functionality */
if (!(err = i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE))) {
- printk(KERN_WARNING
- "TWL4030: SlaveID=%d functionality check failed\n", sid);
+ pr_err("SlaveID=%d functionality check failed\n", sid);
return err;
}
client = &(twl4030_modules[sid]);
if (unlikely(client->inuse)) {
- printk(KERN_ERR "TWL4030: Client is already in Use.....\n");
- printk("%s[ID=0x%x] NOT attached to I2c Adapter %s\n",
- client->client_name, client->address, adapter->name);
+ pr_err("Client %s is already in use\n", client->client_name);
return -EPERM;
}
memcpy(&(client->client.name), client->client_name,
sizeof(TWL_CLIENT_STRING) + 1);
- printk("TWL4030: TRY attach Slave %s on Adapter %s[%d][%x]\n",
- client->client_name, adapter->name, err, err);
- if ((err = i2c_attach_client(&(client->client))))
- printk(KERN_WARNING
- "TWL4030: Couldn't attach Slave %s on Adapter "
- "%s[%d][%x]\n",
- client->client_name, adapter->name, err, err);
- else {
+
+ pr_info("TWL4030: TRY attach Slave %s on Adapter %s [%x]\n",
+ client->client_name, adapter->name, err);
+
+ if ((err = i2c_attach_client(&(client->client)))) {
+ pr_err("Couldn't attach Slave %s on Adapter"
+ "%s [%x]\n", client->client_name, adapter->name, err);
+ } else {
client->inuse = TWL_CLIENT_USED;
init_MUTEX(&client->xfer_lock);
}
+
return err;
}
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) {
return 0;
free_client:
- printk(KERN_ERR
- "TWL4030: TWL_CLIENT(Idx=%d] REGISTRATION FAILED=%d[0x%x]\n", i,
- ret, ret);
+ pr_err("TWL_CLIENT(Idx=%d] registration failed[0x%x]\n",i,ret);
/* ignore current slave..it never got registered */
i--;
{
int err;
if ((err = i2c_detach_client(iclient))) {
- printk(KERN_ERR
- "TWL4030: Client deregistration failed, client not detached.\n");
+ pr_err("Client detach failed\n");
return err;
}
return 0;
{
struct task_struct *thread;
- thread = kthread_create(twl4030_irq_thread, (void *)irq,
- "twl4030 irq %d", irq);
+ init_completion(&irq_event);
+ thread = kthread_run(twl4030_irq_thread, (void *)irq,
+ "twl4030 irq %d", irq);
if (!thread)
- printk(KERN_ERR "%s: could not create twl4030 irq %d thread!\n",
- __FUNCTION__, irq);
+ pr_err("%s: could not create twl4030 irq %d thread!\n",
+ __FUNCTION__, irq);
return thread;
}
static int protect_pm_master(void)
{
int e = 0;
+
e = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_LOCK,
R_PROTECT_KEY);
return e;
static int unprotect_pm_master(void)
{
int e = 0;
+
e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK1,
R_PROTECT_KEY);
e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_UNLOCK2,
return e;
}
-int power_companion_init(void)
+static int power_companion_init(void)
{
struct clk *osc;
u32 rate, ctrl = HFCLK_FREQ_26_MHZ;
static void twl_init_irq(void)
{
- int i = 0;
- int res = 0;
- int line = 0;
+ int i = 0;
+ int res = 0;
+ char *msg = "Unable to register interrupt subsystem";
+
/*
* We end up with interrupts from other modules before
* they get a chance to handle them...
/* PWR_ISR1 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* PWR_ISR2 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* PWR_IMR1 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x1);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* PWR_IMR2 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x3);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* Clear off any other pending interrupts on power */
/* PWR_ISR1 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x00);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* PWR_ISR2 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INT, 0xFF, 0x02);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* POWER HACK (END) */
/* Slave address 0x4A */
/* BCIIMR1_1 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x3);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* BCIIMR1_2 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x4);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* BCIIMR2_1 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x7);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* BCIIMR2_2 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xFF, 0x8);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* MAD C */
/* MADC_IMR1 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x62);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* MADC_IMR2 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, 0xFF, 0x64);
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* key Pad */
/* KEYPAD - IMR1 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x12));
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
{
u8 clear;
/* KEYPAD - IMR2 */
res = twl4030_i2c_write_u8(TWL4030_MODULE_KEYPAD, 0xFF, (0x14));
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* Slave address 0x49 */
/* GPIO_IMR1A */
res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1C));
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* GPIO_IMR2A */
res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1D));
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* GPIO_IMR3A */
res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x1E));
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* GPIO_IMR1B */
res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x22));
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* GPIO_IMR2B */
res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x23));
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* GPIO_IMR3B */
res = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0xFF, (0x24));
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
+ return;
}
/* install an irq handler for each of the PIH modules */
res = power_companion_init();
if (res < 0) {
- line = __LINE__;
- goto irq_exit_path;
+ pr_err("%s[%d][%d]\n", msg, res, __LINE__);
}
-
-irq_exit_path:
- if (res)
- printk(KERN_ERR
- "TWL4030: Unable to register interrupt "
- "subsystem[%d][%d]\n", res, line);
}
static int __init twl4030_init(void)
{
int res;
- if ((res = i2c_register_driver(THIS_MODULE, &twl4030_driver))) {
+
+ if ((res = i2c_add_driver(&twl4030_driver))) {
printk(KERN_ERR "TWL4030: Driver registration failed \n");
return res;
}
- printk(KERN_INFO "TWL4030: Driver registration complete.\n");
- return res;
+
+ pr_info(KERN_INFO "TWL4030: Driver registration complete.\n");
+
+ return 0;
}
static void __exit twl4030_exit(void)
{
- if (i2c_del_driver(&twl4030_driver))
- printk(KERN_ERR
- "TWL4030: Driver remove failed, module not removed\n");
+ i2c_del_driver(&twl4030_driver);
twl_irq_used = FREE;
}