static void pm860x_led_work(struct work_struct *work) { struct pm860x_led *led; struct pm860x_chip *chip; int mask; led = container_of(work, struct pm860x_led, work); chip = led->chip; mutex_lock(&led->lock); if ((led->current_brightness == 0) && led->brightness) { led_power_set(chip, led->port, 1); if (led->iset) { pm860x_set_bits(led->i2c, __led_off(led->port), LED_CURRENT_MASK, led->iset); } pm860x_set_bits(led->i2c, __blink_off(led->port), LED_BLINK_MASK, LED_ON_CONTINUOUS); mask = __blink_ctl_mask(led->port); pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); } else if (led->brightness == 0) { pm860x_set_bits(led->i2c, __led_off(led->port), LED_CURRENT_MASK, 0); mask = __blink_ctl_mask(led->port); pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); led_power_set(chip, led->port, 0); } pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK, led->brightness); led->current_brightness = led->brightness; dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", __led_off(led->port), led->brightness); mutex_unlock(&led->lock); }
static void pm860x_led_work(struct work_struct *work) { struct pm860x_led *led; struct pm860x_chip *chip; unsigned char buf[3]; int mask, ret; led = container_of(work, struct pm860x_led, work); chip = led->chip; mutex_lock(&led->lock); if ((led->current_brightness == 0) && led->brightness) { if (led->iset) { pm860x_set_bits(led->i2c, __led_off(led->port), LED_CURRENT_MASK, led->iset); } pm860x_set_bits(led->i2c, __blink_off(led->port), LED_BLINK_MASK, LED_ON_CONTINUOUS); mask = __blink_ctl_mask(led->port); pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); } pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK, led->brightness); if (led->brightness == 0) { pm860x_bulk_read(led->i2c, __led_off(led->port), 3, buf); ret = buf[0] & LED_PWM_MASK; ret |= buf[1] & LED_PWM_MASK; ret |= buf[2] & LED_PWM_MASK; if (ret == 0) { /* unset current since no led is lighting */ pm860x_set_bits(led->i2c, __led_off(led->port), LED_CURRENT_MASK, 0); mask = __blink_ctl_mask(led->port); pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); } } led->current_brightness = led->brightness; dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", __led_off(led->port), led->brightness); mutex_unlock(&led->lock); }
static int __led_set(struct pm860x_led *led, int command) { struct pm860x_chip *chip = led->chip; int mask, ret; mutex_lock(&led->lock); switch (command) { case SET_BRIGHTNESS: if ((led->current_brightness == 0) && led->brightness) { if (led->iset) { ret = pm860x_set_bits(led->i2c, led->offset, LED_CURRENT_MASK, led->iset); if (ret < 0) goto out; } } else if (led->brightness == 0) { ret = pm860x_set_bits(led->i2c, led->offset, LED_CURRENT_MASK, 0); if (ret < 0) goto out; } ret = pm860x_set_bits(led->i2c, led->offset, LED_PWM_MASK, led->brightness); if (ret < 0) goto out; led->current_brightness = led->brightness; dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", led->offset, led->brightness); break; case SET_BLINK: ret = pm860x_set_bits(led->i2c, led->offset, LED_BLINK_MASK, led->blink_data); if (ret < 0) goto out; mask = __blink_ctl_mask(led->port); ret = pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); if (ret < 0) goto out; dev_dbg(chip->dev, "LED blink delay on:%dms, delay off:%dms\n", led->blink_on, led->blink_off); break; } out: mutex_unlock(&led->lock); return 0; }
static int pm860x_led_blink_handler_thread(void *d) { struct pm860x_led *led =(struct pm860x_led *)d; struct task_struct *tsk = current; struct sched_param param = { .sched_priority = 2 }; DEFINE_WAIT(led_blink_wait); /* set up thread context */ daemonize("pm860x_led_blink_handler_thread"); /* improve pm860x_led_blink_handler_thread priority */ sched_setscheduler(tsk, SCHED_FIFO, ¶m); //for(;;) while(1) { if (0 == led->blink_time) { prepare_to_wait(&led->blink_wait_queue, &led_blink_wait, TASK_INTERRUPTIBLE); if (0 == led->blink_time) schedule(); finish_wait(&led->blink_wait_queue, &led_blink_wait); } try_to_freeze(); if(led->color_green_blink_on && led->color_green_blink_off) { if (led->iset) { pm860x_set_bits(led->i2c, led->color_green_port, LED_CURRENT_MASK, led->iset); } msleep(led->color_green_blink_on); pm860x_set_bits(led->i2c, led->color_green_port, LED_CURRENT_MASK, 0); msleep(led->color_green_blink_off); } else { if (led->iset) { pm860x_set_bits(led->i2c, led->color_green_port, LED_CURRENT_MASK, led->iset); } led->blink_time = 0; } } return 0; } static void pm860x_led_work(struct work_struct *work) { struct pm860x_led *led; struct pm860x_chip *chip; int mask; led = container_of(work, struct pm860x_led, work); chip = led->chip; mutex_lock(&led->lock); if ((led->current_brightness == 0) && led->brightness) { if (led->iset) { pm860x_set_bits(led->i2c, __led_off(led->port), LED_CURRENT_MASK, led->iset); } pm860x_set_bits(led->i2c, __blink_off(led->port), LED_BLINK_MASK, LED_ON_CONTINUOUS); mask = __blink_ctl_mask(led->port); pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); } else if (led->brightness == 0) { pm860x_set_bits(led->i2c, __led_off(led->port), LED_CURRENT_MASK, 0); mask = __blink_ctl_mask(led->port); //pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); } pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK, led->brightness); led->current_brightness = led->brightness; dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", __led_off(led->port), led->brightness); mutex_unlock(&led->lock); } static int pm860x_blink_set(struct led_classdev *cdev, unsigned long *delay_on, unsigned long *delay_off) { struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev); return 1; switch (data->port) { case PM8606_LED1_GREEN: data->color_green_blink_on = *delay_on; data->color_green_blink_off = *delay_off; data->color_green_port = __led_off(data->port); break; default: return 1; } data->blink_time = 1; wake_up_interruptible(&data->blink_wait_queue); return 1; } static void pm860x_led_set(struct led_classdev *cdev, enum led_brightness value) { struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev); data->brightness = value >> 3; if(cdev->flags & LED_SUSPENDED) { pm860x_led_suspend(data); //return; } schedule_work(&data->work); } static int __check_device(struct pm860x_led_pdata *pdata, char *name) { struct pm860x_led_pdata *p = pdata; int ret = -EINVAL; while (p && p->id) { if ((p->id != PM8606_ID_LED) || (p->flags < 0)) break; if (!strncmp(name, pm860x_led_name[p->flags], MFD_NAME_SIZE)) { ret = (int)p->flags; break; } p++; } return ret; } static int pm860x_led_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_platform_data *pm860x_pdata; struct pm860x_led_pdata *pdata; struct pm860x_led *data; struct resource *res; int ret; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res == NULL) { dev_err(&pdev->dev, "No I/O resource!\n"); return -EINVAL; } if (pdev->dev.parent->platform_data) { pm860x_pdata = pdev->dev.parent->platform_data; pdata = pm860x_pdata->led; } else { dev_err(&pdev->dev, "No platform data!\n"); return -EINVAL; } data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL); if (data == NULL) return -ENOMEM; strncpy(data->name, res->name, MFD_NAME_SIZE-1); dev_set_drvdata(&pdev->dev, data); data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; data->iset = pdata->iset; data->port = __check_device(pdata, data->name); if (data->port < 0) { ret = -EINVAL; goto out; } data->current_brightness = 0; data->cdev.name = data->name; data->cdev.brightness_set = pm860x_led_set; data->cdev.blink_set = pm860x_blink_set; mutex_init(&data->lock); INIT_WORK(&data->work, pm860x_led_work); init_waitqueue_head(&data->blink_wait_queue); kernel_thread(pm860x_led_blink_handler_thread, data, 0); data->blink_time = 0; ret = led_classdev_register(chip->dev, &data->cdev); if (ret < 0) { dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); goto out; } return 0; out: kfree(data); return ret; } static int pm860x_led_remove(struct platform_device *pdev) { struct pm860x_led *data = platform_get_drvdata(pdev); led_classdev_unregister(&data->cdev); kfree(data); return 0; } static struct platform_driver pm860x_led_driver = { .driver = { .name = "88pm860x-led", .owner = THIS_MODULE, }, .probe = pm860x_led_probe, .remove = pm860x_led_remove, };