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, "missing 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); 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) { dev_err(&pdev->dev, "check device failed\n"); kfree(data); return -EINVAL; } data->current_brightness = 0; data->cdev.name = data->name; data->cdev.brightness_set = pm860x_led_set; data->cdev.blink_set = pm860x_led_blink; mutex_init(&data->lock); INIT_WORK(&data->work, pm860x_led_work); 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_backlight_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_platform_data *pm860x_pdata; struct pm860x_backlight_pdata *pdata = NULL; struct pm860x_backlight_data *data; struct backlight_device *bl; struct resource *res; struct backlight_properties props; unsigned char value; char name[MFD_NAME_SIZE]; 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->backlight; } if (pdata == NULL) { dev_err(&pdev->dev, "platform data isn't assigned to " "backlight\n"); return -EINVAL; } data = kzalloc(sizeof(struct pm860x_backlight_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; strncpy(name, res->name, MFD_NAME_SIZE); data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client \ : chip->companion; data->current_brightness = MAX_BRIGHTNESS; data->pwm = pdata->pwm; data->iset = pdata->iset; data->port = __check_device(pdata, name); if (data->port < 0) { dev_err(&pdev->dev, "wrong platform data is assigned"); kfree(data); return -EINVAL; } memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = MAX_BRIGHTNESS; bl = backlight_device_register(name, &pdev->dev, data, &pm860x_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); kfree(data); return PTR_ERR(bl); } bl->props.brightness = MAX_BRIGHTNESS; platform_set_drvdata(pdev, bl); /* Enable reference VSYS */ ret = pm860x_reg_read(data->i2c, PM8606_VSYS); if (ret < 0) goto out; if ((ret & PM8606_VSYS_EN) == 0) { value = ret | PM8606_VSYS_EN; ret = pm860x_reg_write(data->i2c, PM8606_VSYS, value); if (ret < 0) goto out; } /* Enable reference OSC */ ret = pm860x_reg_read(data->i2c, PM8606_MISC); if (ret < 0) goto out; if ((ret & PM8606_MISC_OSC_EN) == 0) { value = ret | PM8606_MISC_OSC_EN; ret = pm860x_reg_write(data->i2c, PM8606_MISC, value); if (ret < 0) goto out; } /* read current backlight */ ret = pm860x_backlight_get_brightness(bl); if (ret < 0) goto out; backlight_update_status(bl); return 0; out: backlight_device_unregister(bl); kfree(data); return ret; }
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, };