static int ehrpwm_pwm_start(struct pwm_device *p) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); unsigned short val; unsigned short read_val1; unsigned short read_val2; int chan; 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); ehrpwm_tz_set_action(p, chan, 0x3); read_val1 = ehrpwm_read(ehrpwm, TZFLG); read_val2 = ehrpwm_read(ehrpwm, TZCTL); /* * State of the other channel is determined by reading the * TZCTL register. If the other channel is also in running state, * one shot event status is cleared, otherwise one shot action for * this channel is set to "DO NOTHING. */ read_val2 = read_val2 & (chan ? 0x3 : (0x3 << 2)); read_val2 = chan ? read_val2 : (read_val2 >> 2); if (!(read_val1 & 0x4) || (read_val2 == 0x3)) ehrpwm_tz_clr_evt_status(p); set_bit(FLAG_RUNNING, &p->flags); return 0; }
int ehrpwm_db_get_delay(struct pwm_device *p, unsigned char edge, enum config_mask cfgmask, unsigned long *delay_val) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); unsigned long delay_ns; unsigned long delay_ticks; unsigned char offset; if (!ehrpwm) return -EINVAL; if (edge == RISING_EDGE_DELAY) offset = DBRED; else if (edge == FALLING_EDGE_DELAY) offset = DBFED; else return -EINVAL; delay_ticks = ehrpwm_read(ehrpwm, offset); /* Only least 10 bits are required */ delay_ticks = delay_ticks & 0x3ff; if (cfgmask == CONFIG_TICKS) { *delay_val = delay_ticks * ehrpwm->prescale_val; } else if (cfgmask == CONFIG_NS) { delay_ticks = delay_ticks * ehrpwm->prescale_val; delay_ns = pwm_ticks_to_ns(p, delay_ticks); debug("\n delay ns value is %lu", delay_ns); *delay_val = delay_ns; } else { return -EINVAL; } 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; }
int ehrpwm_tb_read_counter(struct pwm_device *p, unsigned short *val) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); *val = ehrpwm_read(ehrpwm, TBCTR); return 0; }
inline int ehrpwm_tz_read_status(struct pwm_device *p, unsigned short *status) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); *status = ehrpwm_read(ehrpwm, TZFLG); return 0; }
int ehrpwm_tb_read_status(struct pwm_device *p, unsigned short *val) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); *val = ehrpwm_read(ehrpwm, TBSTS); return 0; }
inline int ehrpwm_et_read_int_status(struct pwm_device *p, unsigned long *status) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); *status = ehrpwm_read(ehrpwm, ETFLG) & BIT(0); return 0; }
void ehrpwm_context_save(struct ehrpwm_pwm *ehrpwm, struct ehrpwm_context *ehrpwm_ctx) { pm_runtime_get_sync(ehrpwm->dev); ehrpwm_ctx->tbctl = ehrpwm_read(ehrpwm, TBCTL); ehrpwm_ctx->tbprd = ehrpwm_read(ehrpwm, TBPRD); if (ehrpwm->version == PWM_VERSION_1) ehrpwm_ctx->hrcfg = ehrpwm_read(ehrpwm, AM335X_HRCNFG); else ehrpwm_ctx->hrcfg = ehrpwm_read(ehrpwm, HRCNFG); ehrpwm_ctx->aqctla = ehrpwm_read(ehrpwm, AQCTLA); ehrpwm_ctx->aqctlb = ehrpwm_read(ehrpwm, AQCTLB); ehrpwm_ctx->aqsfrc = ehrpwm_read(ehrpwm, AQSFRC); ehrpwm_ctx->aqcsfrc = ehrpwm_read(ehrpwm, AQCSFRC); ehrpwm_ctx->cmpa = ehrpwm_read(ehrpwm, CMPA); ehrpwm_ctx->cmpb = ehrpwm_read(ehrpwm, CMPB); pm_runtime_put_sync(ehrpwm->dev); }
inline int ehrpwm_et_read_evt_cnt(struct pwm_device *p, unsigned long *evtcnt) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); *evtcnt = ehrpwm_read(ehrpwm, ETPS) & ETPS_INTCNT_MASK; *evtcnt >>= 0x2; return 0; }
inline int ehrpwm_tz_clr_evt_status(struct pwm_device *p) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); unsigned short ret; ret = ehrpwm_read(ehrpwm, TZFLG); ehrpwm_write(ehrpwm, TZCLR, ret & ~0x1); return 0; }
static void ehrpwm_reg_config(struct ehrpwm_pwm *ehrpwm, unsigned int offset, unsigned short val, unsigned short mask) { unsigned short read_val; read_val = ehrpwm_read(ehrpwm, offset); read_val = read_val & ~mask; read_val = read_val | val; ehrpwm_write(ehrpwm, offset, read_val); }
inline int ehrpwm_reg_read(struct pwm_device *p, unsigned int reg, unsigned short *val) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (reg > HRCNFG) return -EINVAL; *val = ehrpwm_read(ehrpwm, reg); return 0; }
static irqreturn_t ehrpwm_trip_zone_irq_handler(int irq, void *data) { struct ehrpwm_pwm *ehrpwm = (struct ehrpwm_pwm *)data; unsigned long flags; int ret = 0; spin_lock_irqsave(&ehrpwm->lock, flags); ret = ehrpwm_read(ehrpwm, TZFLG); if (!(ret & 0x1)) return IRQ_NONE; if (ehrpwm->st_tzint.pcallback) ret = ehrpwm->st_tzint.pcallback(ehrpwm, ehrpwm->st_tzint.data); ret = ehrpwm_read(ehrpwm, TZFLG); ehrpwm_write(ehrpwm, TZCLR, ret & ~0x1); ehrpwm_write(ehrpwm, TZCLR, 0x1); spin_unlock_irqrestore(&ehrpwm->lock, flags); return IRQ_HANDLED; }
static int ehrpwm_pwm_set_prd(struct pwm_device *p) { unsigned int ps_div_val = 1; unsigned int tb_div_val = 0; char ret; unsigned short val; unsigned short period_ticks; struct pwm_device *temp; struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); int chan = 0; /* * Since the device has a singe period register, copy the period * value to the other channel also. */ chan = p - &ehrpwm->pwm[0]; temp = &ehrpwm->pwm[!chan]; temp->period_ticks = p->period_ticks; temp->period_ns = p->period_ns; debug("\n period_ticks is %lu", p->period_ticks); if (p->period_ticks > 65535) { ret = get_divider_val(p->period_ticks / 65535 + 1, &ps_div_val, &tb_div_val); if (ret) { dev_err(p->dev, "failed to get the divider value"); return -EINVAL; } } pm_runtime_get_sync(ehrpwm->dev); val = ehrpwm_read(ehrpwm, TBCTL); val = (val & ~TBCTL_CLKDIV_MASK & ~TBCTL_HSPCLKDIV_MASK) | tb_div_val; ehrpwm_write(ehrpwm, TBCTL, val); period_ticks = p->period_ticks / ps_div_val; if (period_ticks <= 1) { dev_err(p->dev, "Required period/frequency cannot be obtained"); pm_runtime_put_sync(ehrpwm->dev); return -EINVAL; } /* * Program the period register with 1 less than the actual value since * the module generates waveform with period always 1 greater * the programmed value. */ ehrpwm_write(ehrpwm, TBPRD, (unsigned short)(period_ticks - 1)); pm_runtime_put_sync(ehrpwm->dev); debug("\n period_ticks is %d", period_ticks); ehrpwm->prescale_val = ps_div_val; debug("\n Prescaler value is %d", ehrpwm->prescale_val); return 0; }
inline int ehrpwm_reg_read(struct pwm_device *p, unsigned int reg, unsigned short *val) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (!(ehrpwm->version == PWM_VERSION_1)) { if (reg > HRCNFG) return -EINVAL; } *val = ehrpwm_read(ehrpwm, reg); return 0; }
/* Trip Zone configuration functions */ int ehrpwm_tz_sel_event(struct pwm_device *p, unsigned char input, enum tz_event evt) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); unsigned short val = 0; unsigned short mask; unsigned short pos; if (evt > 4 || input > 7) return -EINVAL; switch (evt) { case TZ_ONE_SHOT_EVENT: pos = input + 8; mask = BIT((pos)) | BIT(input); ehrpwm_reg_config(ehrpwm, TZSEL, 1 << pos, mask); break; case TZ_CYCLE_BY_CYCLE: pos = input; mask = BIT(pos) | BIT((pos + 8)); ehrpwm_reg_config(ehrpwm, TZSEL, 1 << pos, mask); break; case TZ_OSHT_CBC: case TZ_DIS_EVT: if (evt == TZ_OSHT_CBC) val = 1; else val = 0; pos = input + 8; mask = BIT((pos)); ehrpwm_reg_config(ehrpwm, TZSEL, val << pos, mask); pos = input; mask = BIT((pos)); ehrpwm_reg_config(ehrpwm, TZSEL, val << pos, mask); break; default: dev_dbg(p->dev, "%s: Invalid command", __func__); return -EINVAL; } debug("\n TZ_sel val is %0x", ehrpwm_read(ehrpwm, TZSEL)); return 0; }
int ehrpwm_tz_set_int_en_dis(struct pwm_device *p, enum tz_event event, unsigned char int_en_dis) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (event == TZ_ONE_SHOT_EVENT) ehrpwm_reg_config(ehrpwm, TZEINT, int_en_dis << TZEINT_OSHTEVT_POS, BIT(2)); else if (event == TZ_CYCLE_BY_CYCLE) ehrpwm_reg_config(ehrpwm, TZEINT, int_en_dis << TZEINT_CBCEVT_POS, BIT(1)); else return -EINVAL; debug("\n TZEINT reg val is %0x", ehrpwm_read(ehrpwm, TZEINT)); return 0; }
int ehrpwm_tz_set_action(struct pwm_device *p, unsigned char ch, unsigned char act) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (act > 0x3 || ch > 1) return -EINVAL; if (ch == 0) ehrpwm_reg_config(ehrpwm, TZCTL, act, TZCTL_ACTA_MASK); else ehrpwm_reg_config(ehrpwm, TZCTL, act << TZCTL_ACTB_POS, TZCTL_ACTB_MASK); debug("\n TZCTL reg val is %0x", ehrpwm_read(ehrpwm, TZCTL)); return 0; }
/* * 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); unsigned short read_val; int chan; chan = p - &ehrpwm->pwm[0]; /* Set the Trip Zone Action to low */ ehrpwm_tz_set_action(p, chan, 0x2); read_val = ehrpwm_read(ehrpwm, TZFLG); /* * If the channel is already in stop state, Trip Zone software force is * not required */ if (!(read_val & 0x4)) { ehrpwm_tz_clr_evt_status(p); ehrpwm_tz_force_evt(p, TZ_ONE_SHOT_EVENT); } clear_bit(FLAG_RUNNING, &p->flags); return 0; }