Skip to content

Commit a0505a7

Browse files
Wenping Zhangrkhuangtao
authored andcommitted
leds: leds-is31fl32xx: merge modifies from develop-3.10.
1. fix cpu stall issue during reboot: In previous code, i2c write and read is executed in function is31fl32xx_brightness_set,this function may be called in softirq context if leds are in timer or oneshot trigger, so there are possibilities cpu will be stalled during led operations. Here we just move the i2c operation to workqueue to make sure not in irq context. 2. fix reboot crash issue. Change-Id: If8520528b092cf4d5c4f1c7dcf2d353acd1c9b9d Signed-off-by: Wenping Zhang <wenping.zhang@rock-chips.com>
1 parent a5763e4 commit a0505a7

1 file changed

Lines changed: 80 additions & 23 deletions

File tree

drivers/leds/leds-is31fl32xx.c

Lines changed: 80 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include <linux/module.h>
2121
#include <linux/of.h>
2222
#include <linux/of_device.h>
23+
#include <linux/delay.h>
24+
#include <linux/of_gpio.h>
25+
#include <linux/gpio.h>
2326

2427
/* Used to indicate a device has no such register */
2528
#define IS31FL32XX_REG_NONE 0xFF
@@ -45,12 +48,16 @@ struct is31fl32xx_led_data {
4548
unsigned int register_delay;
4649
struct device *dev;
4750
struct delayed_work register_work;
51+
struct work_struct brightness_work;
52+
enum led_brightness new_brightness;
4853
};
4954

5055
struct is31fl32xx_priv {
5156
const struct is31fl32xx_chipdef *cdef;
5257
struct i2c_client *client;
5358
unsigned int num_leds;
59+
struct mutex led_mutex;
60+
struct gpio_desc *reset_gpio;
5461
struct is31fl32xx_led_data leds[0];
5562
};
5663

@@ -205,6 +212,33 @@ static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
205212
return is31fl32xx_write(priv, IS31FL3216_CONFIG_REG, value);
206213
}
207214

215+
static void is31fl32xx_brightness_work(struct work_struct *work)
216+
{
217+
const struct is31fl32xx_led_data *led_data =
218+
container_of(work,
219+
struct is31fl32xx_led_data,
220+
brightness_work);
221+
const struct is31fl32xx_chipdef *cdef = led_data->priv->cdef;
222+
u8 pwm_register_offset;
223+
int ret;
224+
225+
dev_dbg(led_data->cdev.dev, "%s: %d\n",
226+
__func__, led_data->new_brightness);
227+
mutex_lock(&led_data->priv->led_mutex);
228+
/* NOTE: led_data->channel is 1-based */
229+
if (cdef->pwm_registers_reversed)
230+
pwm_register_offset = cdef->channels - led_data->channel;
231+
else
232+
pwm_register_offset = led_data->channel - 1;
233+
234+
ret = is31fl32xx_write(led_data->priv,
235+
cdef->pwm_register_base + pwm_register_offset,
236+
led_data->new_brightness);
237+
238+
is31fl32xx_write(led_data->priv, cdef->pwm_update_reg, 0);
239+
mutex_unlock(&led_data->priv->led_mutex);
240+
}
241+
208242
/*
209243
* NOTE: A mutex is not needed in this function because:
210244
* - All referenced data is read-only after probe()
@@ -229,29 +263,11 @@ static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
229263
static void is31fl32xx_brightness_set(struct led_classdev *led_cdev,
230264
enum led_brightness brightness)
231265
{
232-
const struct is31fl32xx_led_data *led_data =
266+
struct is31fl32xx_led_data *led_data =
233267
container_of(led_cdev, struct is31fl32xx_led_data, cdev);
234-
const struct is31fl32xx_chipdef *cdef = led_data->priv->cdef;
235-
u8 pwm_register_offset;
236-
int ret;
237-
238-
dev_dbg(led_cdev->dev, "%s: %d\n", __func__, brightness);
239-
240-
/* NOTE: led_data->channel is 1-based */
241-
if (cdef->pwm_registers_reversed)
242-
pwm_register_offset = cdef->channels - led_data->channel;
243-
else
244-
pwm_register_offset = led_data->channel - 1;
245-
246-
ret = is31fl32xx_write(led_data->priv,
247-
cdef->pwm_register_base + pwm_register_offset,
248-
brightness);
249-
if (ret)
250-
dev_err(led_cdev->dev,
251-
"set brightness %d for led[%d] failed\n",
252-
brightness, pwm_register_offset);
253268

254-
is31fl32xx_write(led_data->priv, cdef->pwm_update_reg, 0);
269+
led_data->new_brightness = brightness;
270+
schedule_work(&led_data->brightness_work);
255271
}
256272

257273
static int is31fl32xx_reset_regs(struct is31fl32xx_priv *priv)
@@ -298,7 +314,7 @@ static int is31fl32xx_init_regs(struct is31fl32xx_priv *priv)
298314

299315
ret = is31fl32xx_reset_regs(priv);
300316
if (ret)
301-
return ret;
317+
pr_err("%s, write to reset register failed\n", __func__);
302318

303319
/*
304320
* Set enable bit for all channels.
@@ -377,6 +393,7 @@ static int is31fl32xx_parse_child_dt(const struct device *dev,
377393

378394
cdev->brightness_set = is31fl32xx_brightness_set;
379395

396+
INIT_WORK(&led_data->brightness_work, is31fl32xx_brightness_work);
380397
return 0;
381398
}
382399

@@ -482,24 +499,39 @@ static int is31fl32xx_probe(struct i2c_client *client,
482499
struct is31fl32xx_priv *priv;
483500
int count;
484501
int ret = 0;
502+
struct gpio_desc *gpio;
485503

486504
of_dev_id = of_match_device(of_is31fl32xx_match, dev);
487505
if (!of_dev_id)
488506
return -EINVAL;
489507

508+
gpio = devm_gpiod_get_optional(dev,
509+
"reset", GPIOD_OUT_HIGH);
510+
if (IS_ERR(gpio)) {
511+
int error = PTR_ERR(gpio);
512+
513+
dev_err(dev, "Failed to get reset gpio: %d\n", error);
514+
return -EINVAL;
515+
}
516+
gpiod_direction_output(gpio, 1);
517+
490518
cdef = of_dev_id->data;
491519

492520
count = of_get_child_count(dev->of_node);
493-
if (!count)
521+
if (!count) {
522+
dev_err(dev, "count is invalid\n");
494523
return -EINVAL;
524+
}
495525

496526
priv = devm_kzalloc(dev, sizeof_is31fl32xx_priv(count),
497527
GFP_KERNEL);
498528
if (!priv)
499529
return -ENOMEM;
500530

531+
mutex_init(&priv->led_mutex);
501532
priv->client = client;
502533
priv->cdef = cdef;
534+
priv->reset_gpio = gpio;
503535
i2c_set_clientdata(client, priv);
504536

505537
ret = is31fl32xx_init_regs(priv);
@@ -515,11 +547,35 @@ static int is31fl32xx_probe(struct i2c_client *client,
515547

516548
static int is31fl32xx_remove(struct i2c_client *client)
517549
{
550+
int i;
518551
struct is31fl32xx_priv *priv = i2c_get_clientdata(client);
519552

553+
for (i = 0; i < priv->num_leds; i++) {
554+
struct is31fl32xx_led_data *led_data =
555+
&priv->leds[i];
556+
cancel_delayed_work_sync(&led_data->register_work);
557+
cancel_work_sync(&led_data->brightness_work);
558+
}
559+
520560
return is31fl32xx_reset_regs(priv);
521561
}
522562

563+
static void is31fl32xx_shutdown(struct i2c_client *client)
564+
{
565+
int i;
566+
struct is31fl32xx_priv *priv = i2c_get_clientdata(client);
567+
568+
for (i = 0; i < priv->num_leds; i++) {
569+
struct is31fl32xx_led_data *led_data =
570+
&priv->leds[i];
571+
cancel_delayed_work_sync(&led_data->register_work);
572+
cancel_work_sync(&led_data->brightness_work);
573+
}
574+
575+
is31fl32xx_reset_regs(priv);
576+
gpiod_set_value(priv->reset_gpio, 0);
577+
}
578+
523579
/*
524580
* i2c-core (and modalias) requires that id_table be properly filled,
525581
* even though it is not used for DeviceTree based instantiation.
@@ -543,6 +599,7 @@ static struct i2c_driver is31fl32xx_driver = {
543599
},
544600
.probe = is31fl32xx_probe,
545601
.remove = is31fl32xx_remove,
602+
.shutdown = is31fl32xx_shutdown,
546603
.id_table = is31fl32xx_id,
547604
};
548605

0 commit comments

Comments
 (0)