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);
}
Пример #2
0
static int pm860x_led_blink(struct led_classdev *cdev,
			    unsigned long *delay_on,
			    unsigned long *delay_off)
{
	struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev);
	int period, on;

	on = *delay_on;
	if ((on < LED_BLINK_ON_MIN) || (on > LED_BLINK_ON_MAX))
		return -EINVAL;

	on = LED_TO_ON(on);
	on = LED_BLINK_ON(on);

	period = on + *delay_off;
	if ((period < LED_BLINK_PERIOD_MIN) || (period > LED_BLINK_PERIOD_MAX))
		return -EINVAL;
	period = LED_TO_PERIOD(period);
	period = LED_BLINK_PERIOD(period);

	data->offset = __blink_off(data->port);
	data->blink_on = on;
	data->blink_off = period - data->blink_on;
	data->blink_data = (period << 3) | data->blink_on;
	data->command = SET_BLINK;
	schedule_work(&data->work);

	return 0;
}
Пример #3
0
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);
}
Пример #4
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, &param);
	
	//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,
};