Beispiel #1
0
static inline struct ecap_pwm *to_ecap_pwm(const struct pwm_device *p)
{
	return pwm_get_drvdata(p);
}
static int kona_pwmc_config(struct pwm_device *p, struct pwm_config *c)
{
	struct kona_pwmc *ap = pwm_get_drvdata(p);
	int chan = kona_get_chan(ap, p);
	int ret = 0;

	if (test_bit(PWM_CONFIG_POLARITY, &c->config_mask))
		kona_pwmc_config_polarity(ap, chan, c);

	if (test_bit(PWM_CONFIG_DUTY_TICKS, &c->config_mask))
		kona_pwmc_config_duty_ticks(ap, chan, c);

	if (test_bit(PWM_CONFIG_PERIOD_TICKS, &c->config_mask)) {
		ret = kona_pwmc_config_period_ticks(ap, chan, c);
		if (ret)
			goto out;

		if (!test_bit(PWM_CONFIG_DUTY_TICKS, &c->config_mask)) {
			struct pwm_config d = {
				.config_mask = PWM_CONFIG_DUTY_TICKS,
				.duty_ticks = p->duty_ticks,
			};
			kona_pwmc_config_duty_ticks(ap, chan, &d);
		}
	}

	if (!ap->pwm_started && test_bit(PWM_CONFIG_START, &c->config_mask)) {
		/* Restore duty ticks cater for STOP case. */
		struct pwm_config d = {
			.config_mask = PWM_CONFIG_DUTY_TICKS,
			.duty_ticks = p->duty_ticks,
		};

		ap->pwm_started = 1;
		usleep_range(3000, 7000);
		clk_enable(ap->clk);
		kona_pwmc_clear_set_bit(ap, pwm_chan_ctrl_info[chan].offset,
					pwm_chan_ctrl_info[chan].
					smooth_type_shift, 1);
		kona_pwmc_config_duty_ticks(ap, chan, &d);
		kona_pwmc_start(ap, chan);
	}

	if (ap->pwm_started && test_bit(PWM_CONFIG_STOP, &c->config_mask)) {
		struct pwm_config d = {
			.config_mask = PWM_CONFIG_DUTY_TICKS,
			.duty_ticks = 0,
		};

		ap->pwm_started = 0;
		kona_pwmc_config_duty_ticks(ap, chan, &d);
		kona_pwmc_clear_set_bit(ap, pwm_chan_ctrl_info[chan].offset,
					pwm_chan_ctrl_info[chan].
					smooth_type_shift, 0);
		/* turn-off the PWM clock i.e. enabled during pwm_start */
		ndelay(410);
		clk_disable(ap->clk);
	}

out:
	return ret;
}

static int kona_pwmc_request(struct pwm_device *p)
{
	struct kona_pwmc *ap = pwm_get_drvdata(p);
	int chan = kona_get_chan(ap, p);
	clk_enable(ap->clk);
	p->tick_hz = clk_get_rate(ap->clk);
	kona_pwmc_stop(ap, chan);
	clk_disable(ap->clk);
	return 0;
}

static void kona_pwmc_release(struct pwm_device *p)
{

}


static const struct pwm_device_ops kona_pwm_ops = {
	.request = kona_pwmc_request,
	.release = kona_pwmc_release,
	.config = kona_pwmc_config,
	.owner = THIS_MODULE,
};

static int __devinit kona_pwmc_probe(struct platform_device *pdev)
{
	struct kona_pwmc *ap;
	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	int chan;
	int ret = 0;

	ap = kzalloc(sizeof(*ap), GFP_KERNEL);
	if (!ap) {
		ret = -ENOMEM;
		goto err_kona_pwmc_alloc;
	}

	platform_set_drvdata(pdev, ap);
	ap->clk = clk_get(&pdev->dev, "pwm_clk");
	if (IS_ERR(ap->clk)) {
		ret = -ENODEV;
		goto err_clk_get;
	}

	ap->iobase = ioremap_nocache(r->start, resource_size(r));
	if (!ap->iobase) {
		ret = -ENODEV;
		goto err_ioremap;
	}

	for (chan = 0; chan < KONA_PWM_CHANNEL_CNT; chan++) {
		ap->p[chan] = pwm_register(&kona_pwm_ops, &pdev->dev, "%s:%d",
					   "kona_pwmc", chan);
		if (IS_ERR_OR_NULL(ap->p[chan]))
			goto err_pwm_register;
		pwm_set_drvdata(ap->p[chan], ap);
		kona_pwmc_clear_set_bit(ap, pwm_chan_ctrl_info[chan].offset,
					pwm_chan_ctrl_info[chan].
					smooth_type_shift, 1);
	}

	printk(KERN_INFO "PWM: driver initialized properly");

	return 0;

err_pwm_register:
	while (--chan > 0)
		pwm_unregister(ap->p[chan]);

	iounmap(ap->iobase);
err_ioremap:
	clk_put(ap->clk);
err_clk_get:
	platform_set_drvdata(pdev, NULL);
	kfree(ap);
err_kona_pwmc_alloc:
	printk(KERN_ERR "%s: error, returning %d\n", __func__, ret);
	return ret;
}

static int __devexit kona_pwmc_remove(struct platform_device *pdev)
{
	struct kona_pwmc *ap = platform_get_drvdata(pdev);
	int chan;

	for (chan = 0; chan < KONA_PWM_CHANNEL_CNT; chan++)
		pwm_unregister(ap->p[chan]);

	clk_put(ap->clk);
	iounmap(ap->iobase);

	kfree(ap);

	return 0;
}

#ifdef CONFIG_PM
static int kona_pwmc_suspend(struct platform_device *pdev, pm_message_t state)
{
	/* TODO: add more resume support in the future */
	return 0;
}

static int kona_pwmc_resume(struct platform_device *pdev)
{
	/* TODO: add more resume support in the future */
	return 0;
}
#else
#define kona_pwmc_suspend    NULL
#define kona_pwmc_resume     NULL
#endif

static const struct of_device_id kona_pwmc_dt_ids[] = {
	{ .compatible = "bcm,pwmc", },
	{}
};