static int ecap_pwm_config_duty(struct pwm_device *p) { unsigned long flags, v; struct ecap_pwm *ep = to_ecap_pwm(p); pm_runtime_get_sync(ep->dev); spin_lock_irqsave(&ep->lock, flags); v = readw(ep->mmio_base + CAPTURE_CTRL2_REG); v |= (ECTRL2_MDSL_ECAP | ECTRL2_SYNCOSEL_MASK); writew(v, ep->mmio_base + CAPTURE_CTRL2_REG); if (p->duty_ticks > 0) { writel(p->duty_ticks, ep->mmio_base + CAPTURE_4_REG); } else { writel(p->duty_ticks, ep->mmio_base + CAPTURE_2_REG); writel(0, ep->mmio_base + TIMER_CTR_REG); } spin_unlock_irqrestore(&ep->lock, flags); if (!pwm_is_running(p)) { v = readw(ep->mmio_base + CAPTURE_CTRL2_REG); v &= ~ECTRL2_MDSL_ECAP; writew(v, ep->mmio_base + CAPTURE_CTRL2_REG); } pm_runtime_put_sync(ep->dev); return 0; }
static int ehrpwm_pwm_start(struct pwm_device *p) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); unsigned short val; int chan; /* Trying to start a running PWM, not allowed */ if (pwm_is_running(p)) return -EPERM; /* For PWM clock should be enabled on start */ pm_runtime_get_sync(ehrpwm->dev); ehrpwm_pwm_set_pol(p); chan = p - &ehrpwm->pwm[0]; val = ehrpwm_read(ehrpwm, TBCTL); val = (val & ~TBCTL_CTRMODE_MASK) | (TBCTL_CTRMOD_CTRUP | TBCTL_FREERUN_FREE << 14); ehrpwm_write(ehrpwm, TBCTL, val); /* Enable PWM channel output */ ehrpwm_channel_output_enable(p, chan); set_bit(FLAG_RUNNING, &p->flags); return 0; }
static ssize_t pwm_run_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pwm_device *p = dev_get_drvdata(dev); return sprintf(buf, "%d\n", pwm_is_running(p)); }
/* * Stop function is implemented using the Trip Zone module. Action for the * corresponding channel is set to low and the one shot software force * event is triggered. */ static int ehrpwm_pwm_stop(struct pwm_device *p) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); /* Trying to stop a non-running PWM, not allowed */ if (!pwm_is_running(p)) return -EPERM; /* Put PWM output to low */ ehrpwm_channel_output_low(p); /* For PWM clock should be disabled on stop */ pm_runtime_put_sync(ehrpwm->dev); clear_bit(FLAG_RUNNING, &p->flags); return 0; }
static int ehrpwm_freq_transition_cb(struct pwm_device *p) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); unsigned long duty_ns; p->tick_hz = clk_get_rate(ehrpwm->clk); duty_ns = p->duty_ns; if (pwm_is_running(p)) { pwm_stop(p); pwm_set_duty_ns(p, 0); pwm_set_period_ns(p, p->period_ns); pwm_set_duty_ns(p, duty_ns); pwm_start(p); } else { pwm_set_duty_ns(p, 0); pwm_set_period_ns(p, p->period_ns); pwm_set_duty_ns(p, duty_ns); } return 0; }
int pwm_unregister(struct pwm_device *p) { int ret = 0; mutex_lock(&device_list_mutex); if (pwm_is_running(p) || pwm_is_requested(p)) { ret = -EBUSY; goto done; } sysfs_remove_group(&p->dev->kobj, &pwm_device_attr_group); device_unregister(p->dev); p->flags = 0; done: mutex_unlock(&device_list_mutex); return ret; }
static int ecap_pwm_stop(struct pwm_device *p) { unsigned long flags, v; struct ecap_pwm *ep = to_ecap_pwm(p); /* Trying to stop a non-running PWM, not allowed */ if (!pwm_is_running(p)) return -EPERM; spin_lock_irqsave(&ep->lock, flags); v = readw(ep->mmio_base + CAPTURE_CTRL2_REG); v &= ~(ECTRL2_CTRSTP_FREERUN | ECTRL2_MDSL_ECAP); writew(v, ep->mmio_base + CAPTURE_CTRL2_REG); spin_unlock_irqrestore(&ep->lock, flags); /* For PWM clock should be disabled on stop */ pm_runtime_put_sync(ep->dev); clear_bit(FLAG_RUNNING, &p->flags); return 0; }
static int ecap_pwm_start(struct pwm_device *p) { int ret = 0; unsigned long flags, v; struct ecap_pwm *ep = to_ecap_pwm(p); /* Trying to start a running PWM, not allowed */ if (pwm_is_running(p)) return -EPERM; /* For PWM clock should be enabled on start */ pm_runtime_get_sync(ep->dev); spin_lock_irqsave(&ep->lock, flags); v = readw(ep->mmio_base + CAPTURE_CTRL2_REG); v |= (ECTRL2_CTRSTP_FREERUN | ECTRL2_MDSL_ECAP); writew(v, ep->mmio_base + CAPTURE_CTRL2_REG); spin_unlock_irqrestore(&ep->lock, flags); set_bit(FLAG_RUNNING, &p->flags); return ret; }
static int ecap_frequency_transition_cb(struct pwm_device *p) { struct ecap_pwm *ep = to_ecap_pwm(p); unsigned long duty_ns, rate; rate = clk_get_rate(ep->clk); if (rate == p->tick_hz) return 0; p->tick_hz = rate; duty_ns = p->duty_ns; if (pwm_is_running(p)) { pwm_stop(p); pwm_set_duty_ns(p, 0); pwm_set_period_ns(p, p->period_ns); pwm_set_duty_ns(p, duty_ns); pwm_start(p); } else { pwm_set_duty_ns(p, 0); pwm_set_period_ns(p, p->period_ns); pwm_set_duty_ns(p, duty_ns); } return 0; }