isl29023: add delayed work driven mode

This commit is contained in:
Dalingrin
2012-02-16 19:25:07 -06:00
committed by James Sullins
parent d89743aa9b
commit 2f74e199db
2 changed files with 65 additions and 22 deletions

View File

@@ -62,12 +62,15 @@ struct isl29023_data {
struct mutex lock; struct mutex lock;
struct input_dev *input; struct input_dev *input;
struct work_struct work; struct work_struct work;
struct delayed_work polled_work;
struct workqueue_struct *workqueue; struct workqueue_struct *workqueue;
char phys[32]; char phys[32];
u8 reg_cache[ISL29023_NUM_CACHABLE_REGS]; u8 reg_cache[ISL29023_NUM_CACHABLE_REGS];
u8 mode_before_suspend; u8 mode_before_suspend;
u8 mode_before_interrupt; u8 mode_before_interrupt;
u16 rext; u16 rext;
u8 polled;
u16 poll_interval;
}; };
static int gain_range[] = { static int gain_range[] = {
@@ -286,10 +289,21 @@ static int isl29023_set_mode(struct i2c_client *client, int mode)
/* power_state */ /* power_state */
static int isl29023_set_power_state(struct i2c_client *client, int state) static int isl29023_set_power_state(struct i2c_client *client, int state)
{ {
return __isl29023_write_reg(client, ISL29023_COMMAND1, struct isl29023_data *data = i2c_get_clientdata(client);
int rc = __isl29023_write_reg(client, ISL29023_COMMAND1,
ISL29023_MODE_MASK, ISL29023_MODE_SHIFT, ISL29023_MODE_MASK, ISL29023_MODE_SHIFT,
state ? state ?
ISL29023_ALS_ONCE_MODE : ISL29023_PD_MODE); ISL29023_ALS_ONCE_MODE : ISL29023_PD_MODE);
if (data->polled) {
if (state)
schedule_delayed_work(&data->polled_work,
msecs_to_jiffies(data->poll_interval));
else
cancel_delayed_work_sync(&data->polled_work);
}
return rc;
} }
static int isl29023_get_power_state(struct i2c_client *client) static int isl29023_get_power_state(struct i2c_client *client)
@@ -587,7 +601,7 @@ static ssize_t isl29023_store_mode(struct device *dev,
return count; return count;
} }
static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO, static DEVICE_ATTR(mode, 0666,
isl29023_show_mode, isl29023_store_mode); isl29023_show_mode, isl29023_store_mode);
@@ -612,10 +626,11 @@ static ssize_t isl29023_store_power_state(struct device *dev,
return -EINVAL; return -EINVAL;
ret = isl29023_set_power_state(client, val); ret = isl29023_set_power_state(client, val);
return ret ? ret : count; return ret ? ret : count;
} }
static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, static DEVICE_ATTR(power_state, 0666,
isl29023_show_power_state, isl29023_store_power_state); isl29023_show_power_state, isl29023_store_power_state);
/* lux */ /* lux */
@@ -818,25 +833,43 @@ static int isl29023_init_client(struct i2c_client *client)
static void isl29023_work(struct work_struct *work) static void isl29023_work(struct work_struct *work)
{ {
struct i2c_client *client;
int lux;
struct isl29023_data *data = struct isl29023_data *data =
container_of(work, struct isl29023_data, work); container_of(work, struct isl29023_data, work);
struct i2c_client *client = data->client;
int lux;
struct isl29023_data *data_polled =
container_of((struct delayed_work *)work, struct isl29023_data,
polled_work);
if (data_polled->polled)
data = data_polled;
client = data->client;
if (!data->polled) {
/* Clear interrupt flag */ /* Clear interrupt flag */
isl29023_set_int_flag(client, 0); isl29023_set_int_flag(client, 0);
data->mode_before_interrupt = isl29023_get_mode(client); data->mode_before_interrupt = isl29023_get_mode(client);
}
lux = isl29023_get_adc_value(client); lux = isl29023_get_adc_value(client);
if (!data->polled) {
/* To clear the interrpt status */ /* To clear the interrpt status */
isl29023_set_power_state(client, ISL29023_PD_MODE); isl29023_set_power_state(client, ISL29023_PD_MODE);
isl29023_set_mode(client, data->mode_before_interrupt); isl29023_set_mode(client, data->mode_before_interrupt);
}
msleep(100); msleep(100);
input_report_abs(data->input, ABS_MISC, lux); input_report_abs(data->input, ABS_MISC, lux);
input_sync(data->input); input_sync(data->input);
if(data->polled) {
schedule_delayed_work(&data->polled_work,
msecs_to_jiffies(data->poll_interval));
}
} }
static irqreturn_t isl29023_irq_handler(int irq, void *handle) static irqreturn_t isl29023_irq_handler(int irq, void *handle)
@@ -871,6 +904,8 @@ static int __devinit isl29023_probe(struct i2c_client *client,
data->client = client; data->client = client;
data->rext = ls_data->rext; data->rext = ls_data->rext;
data->polled = ls_data->polled;
data->poll_interval = ls_data->poll_interval;
snprintf(data->phys, sizeof(data->phys), snprintf(data->phys, sizeof(data->phys),
"%s", dev_name(&client->dev)); "%s", dev_name(&client->dev));
i2c_set_clientdata(client, data); i2c_set_clientdata(client, data);
@@ -905,6 +940,7 @@ static int __devinit isl29023_probe(struct i2c_client *client,
if (err) if (err)
goto exit_free_input; goto exit_free_input;
if (!data->polled) {
/* set irq type to edge falling */ /* set irq type to edge falling */
irq_set_irq_type(client->irq, IRQF_TRIGGER_FALLING); irq_set_irq_type(client->irq, IRQF_TRIGGER_FALLING);
err = request_irq(client->irq, isl29023_irq_handler, 0, err = request_irq(client->irq, isl29023_irq_handler, 0,
@@ -914,6 +950,9 @@ static int __devinit isl29023_probe(struct i2c_client *client,
client->irq); client->irq);
goto exit_free_input; goto exit_free_input;
} }
} else {
INIT_DELAYED_WORK(&data->polled_work, isl29023_work);
}
data->workqueue = create_singlethread_workqueue("isl29023"); data->workqueue = create_singlethread_workqueue("isl29023");
INIT_WORK(&data->work, isl29023_work); INIT_WORK(&data->work, isl29023_work);
@@ -939,6 +978,8 @@ static int __devexit isl29023_remove(struct i2c_client *client)
{ {
struct isl29023_data *data = i2c_get_clientdata(client); struct isl29023_data *data = i2c_get_clientdata(client);
if (data->polled)
cancel_delayed_work_sync(&data->polled_work);
cancel_work_sync(&data->work); cancel_work_sync(&data->work);
destroy_workqueue(data->workqueue); destroy_workqueue(data->workqueue);
free_irq(client->irq, data); free_irq(client->irq, data);

View File

@@ -47,6 +47,8 @@
struct isl29023_platform_data { struct isl29023_platform_data {
char *vdd_reg; char *vdd_reg;
int rext; int rext;
int polled;
int poll_interval;
}; };
#endif #endif