isl29023: add delayed work driven mode
This commit is contained in:
@@ -62,12 +62,15 @@ struct isl29023_data {
|
||||
struct mutex lock;
|
||||
struct input_dev *input;
|
||||
struct work_struct work;
|
||||
struct delayed_work polled_work;
|
||||
struct workqueue_struct *workqueue;
|
||||
char phys[32];
|
||||
u8 reg_cache[ISL29023_NUM_CACHABLE_REGS];
|
||||
u8 mode_before_suspend;
|
||||
u8 mode_before_interrupt;
|
||||
u16 rext;
|
||||
u8 polled;
|
||||
u16 poll_interval;
|
||||
};
|
||||
|
||||
static int gain_range[] = {
|
||||
@@ -286,10 +289,21 @@ static int isl29023_set_mode(struct i2c_client *client, int mode)
|
||||
/* power_state */
|
||||
static int isl29023_set_power_state(struct i2c_client *client, int state)
|
||||
{
|
||||
return __isl29023_write_reg(client, ISL29023_COMMAND1,
|
||||
ISL29023_MODE_MASK, ISL29023_MODE_SHIFT,
|
||||
state ?
|
||||
ISL29023_ALS_ONCE_MODE : ISL29023_PD_MODE);
|
||||
struct isl29023_data *data = i2c_get_clientdata(client);
|
||||
|
||||
int rc = __isl29023_write_reg(client, ISL29023_COMMAND1,
|
||||
ISL29023_MODE_MASK, ISL29023_MODE_SHIFT,
|
||||
state ?
|
||||
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)
|
||||
@@ -587,7 +601,7 @@ static ssize_t isl29023_store_mode(struct device *dev,
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO,
|
||||
static DEVICE_ATTR(mode, 0666,
|
||||
isl29023_show_mode, isl29023_store_mode);
|
||||
|
||||
|
||||
@@ -612,10 +626,11 @@ static ssize_t isl29023_store_power_state(struct device *dev,
|
||||
return -EINVAL;
|
||||
|
||||
ret = isl29023_set_power_state(client, val);
|
||||
|
||||
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);
|
||||
|
||||
/* lux */
|
||||
@@ -818,25 +833,43 @@ static int isl29023_init_client(struct i2c_client *client)
|
||||
|
||||
static void isl29023_work(struct work_struct *work)
|
||||
{
|
||||
struct isl29023_data *data =
|
||||
container_of(work, struct isl29023_data, work);
|
||||
struct i2c_client *client = data->client;
|
||||
struct i2c_client *client;
|
||||
int lux;
|
||||
struct isl29023_data *data =
|
||||
container_of(work, struct isl29023_data, work);
|
||||
|
||||
/* Clear interrupt flag */
|
||||
isl29023_set_int_flag(client, 0);
|
||||
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 */
|
||||
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);
|
||||
|
||||
if (!data->polled) {
|
||||
/* To clear the interrpt status */
|
||||
isl29023_set_power_state(client, ISL29023_PD_MODE);
|
||||
isl29023_set_mode(client, data->mode_before_interrupt);
|
||||
isl29023_set_power_state(client, ISL29023_PD_MODE);
|
||||
isl29023_set_mode(client, data->mode_before_interrupt);
|
||||
}
|
||||
|
||||
msleep(100);
|
||||
|
||||
input_report_abs(data->input, ABS_MISC, lux);
|
||||
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)
|
||||
@@ -871,6 +904,8 @@ static int __devinit isl29023_probe(struct i2c_client *client,
|
||||
|
||||
data->client = client;
|
||||
data->rext = ls_data->rext;
|
||||
data->polled = ls_data->polled;
|
||||
data->poll_interval = ls_data->poll_interval;
|
||||
snprintf(data->phys, sizeof(data->phys),
|
||||
"%s", dev_name(&client->dev));
|
||||
i2c_set_clientdata(client, data);
|
||||
@@ -905,14 +940,18 @@ static int __devinit isl29023_probe(struct i2c_client *client,
|
||||
if (err)
|
||||
goto exit_free_input;
|
||||
|
||||
/* set irq type to edge falling */
|
||||
irq_set_irq_type(client->irq, IRQF_TRIGGER_FALLING);
|
||||
err = request_irq(client->irq, isl29023_irq_handler, 0,
|
||||
client->dev.driver->name, data);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "failed to register irq %d!\n",
|
||||
client->irq);
|
||||
goto exit_free_input;
|
||||
if (!data->polled) {
|
||||
/* set irq type to edge falling */
|
||||
irq_set_irq_type(client->irq, IRQF_TRIGGER_FALLING);
|
||||
err = request_irq(client->irq, isl29023_irq_handler, 0,
|
||||
client->dev.driver->name, data);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "failed to register irq %d!\n",
|
||||
client->irq);
|
||||
goto exit_free_input;
|
||||
}
|
||||
} else {
|
||||
INIT_DELAYED_WORK(&data->polled_work, isl29023_work);
|
||||
}
|
||||
|
||||
data->workqueue = create_singlethread_workqueue("isl29023");
|
||||
@@ -939,6 +978,8 @@ static int __devexit isl29023_remove(struct i2c_client *client)
|
||||
{
|
||||
struct isl29023_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (data->polled)
|
||||
cancel_delayed_work_sync(&data->polled_work);
|
||||
cancel_work_sync(&data->work);
|
||||
destroy_workqueue(data->workqueue);
|
||||
free_irq(client->irq, data);
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
struct isl29023_platform_data {
|
||||
char *vdd_reg;
|
||||
int rext;
|
||||
int polled;
|
||||
int poll_interval;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user