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", }, {} };