int ehrpwm_aq_set_act_ctrl(struct pwm_device *p, struct aq_config_params *cfg) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); unsigned char reg; if (!cfg) return -EINVAL; if (cfg->ch > 1 || cfg->ctreqzro > 3 || cfg->ctreqprd > 3 || cfg->ctreqcmpaup > 3 || cfg->ctreqcmpadown > 3 || cfg->ctreqcmpbup > 3 || cfg->ctreqcmpbdown > 3) return -EINVAL; if (cfg->ch == 0) reg = AQCTLA; else reg = AQCTLB; ehrpwm_reg_config(ehrpwm, reg, cfg->ctreqzro, ACTCTL_CZRO_MASK); ehrpwm_reg_config(ehrpwm, reg, cfg->ctreqprd << ACTCTL_CTREQPRD_POS, ACTCTL_CPRD_MASK); ehrpwm_reg_config(ehrpwm, reg, cfg->ctreqcmpaup << ACTCTL_CTREQCMPAUP_POS, ACTCTL_CAU_MASK); ehrpwm_reg_config(ehrpwm, reg, cfg->ctreqcmpadown << ACTCTL_CTREQCMPADN_POS, ACTCTL_CAD_MASK); ehrpwm_reg_config(ehrpwm, reg, cfg->ctreqcmpbup << ACTCTL_CTREQCMPBUP_POS, ACTCTL_CBU_MASK); ehrpwm_reg_config(ehrpwm, reg, cfg->ctreqcmpbdown << ACTCTL_CTREQCMPBDN_POS, ACTCTL_CBD_MASK); return 0; }
int ehrpwm_hr_config(struct pwm_device *p, unsigned char loadmode, unsigned char ctlmode, unsigned char edgemode) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (loadmode > 1 || ctlmode > 1 || edgemode > 3) return -EINVAL; if (ehrpwm->version == PWM_VERSION_1) { ehrpwm_reg_config(ehrpwm, AM335X_HRCNFG, loadmode << HRCNFG_LDMD_POS, BIT(3)); ehrpwm_reg_config(ehrpwm, AM335X_HRCNFG, ctlmode << HRCNFG_CTLMD_POS, BIT(2)); ehrpwm_reg_config(ehrpwm, AM335X_HRCNFG, edgemode, HRCNFG_EDGEMD_MASK); } else { ehrpwm_reg_config(ehrpwm, HRCNFG, loadmode << HRCNFG_LDMD_POS, BIT(3)); ehrpwm_reg_config(ehrpwm, HRCNFG, ctlmode << HRCNFG_CTLMD_POS, BIT(2)); ehrpwm_reg_config(ehrpwm, HRCNFG, edgemode, HRCNFG_EDGEMD_MASK); } return 0; }
static int ehrpwm_pwm_set_dty(struct pwm_device *p) { unsigned short duty_ticks = 0; struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); int ret = 0; int chan; chan = p - &ehrpwm->pwm[0]; if (!ehrpwm->prescale_val) { dev_dbg(p->dev, "%s: prescale_val is zero\n", __func__); return -EINVAL; } duty_ticks = p->duty_ticks / ehrpwm->prescale_val; debug("\n Prescaler value is %d", ehrpwm->prescale_val); debug("\n duty ticks is %d", duty_ticks); pm_runtime_get_sync(ehrpwm->dev); /* High resolution module */ if (chan && ehrpwm->prescale_val <= 1) { ret = ehrpwm_hr_duty_config(p); if (ehrpwm->version == PWM_VERSION_1) ehrpwm_write(ehrpwm, AM335X_HRCNFG, 0x2); else ehrpwm_write(ehrpwm, HRCNFG, 0x2); } ehrpwm_write(ehrpwm, (chan ? CMPB : CMPA), duty_ticks); pm_runtime_put_sync(ehrpwm->dev); return ret; }
static int ehrpwm_hr_duty_config(struct pwm_device *p) { unsigned char no_of_mepsteps; unsigned short cmphr_val; struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (!p->tick_hz) { dev_dbg(p->dev, "%s: p->tick_hz is zero\n", __func__); return -EINVAL; } /* * Calculate the no of MEP steps. Assume system clock * is in the order of MHZ. */ no_of_mepsteps = USEC_PER_SEC / ((p->tick_hz / USEC_PER_SEC) * 63); pm_runtime_get_sync(ehrpwm->dev); /* Calculate the CMPHR Value */ cmphr_val = p->tick_hz / USEC_PER_SEC; cmphr_val = (p->duty_ns * cmphr_val) % MSEC_PER_SEC; cmphr_val = (cmphr_val * no_of_mepsteps) / 1000; cmphr_val = (cmphr_val << 8) + 0x180; ehrpwm_write(ehrpwm, CMPAHR, cmphr_val); if (ehrpwm->version == PWM_VERSION_1) ehrpwm_write(ehrpwm, AM335X_HRCNFG, 0x2); else ehrpwm_write(ehrpwm, HRCNFG, 0x2); pm_runtime_put_sync(ehrpwm->dev); return 0; }
static int ehrpwm_pwm_set_pol(struct pwm_device *p) { unsigned int act_ctrl_reg; unsigned int cmp_reg; unsigned int ctreqcmp_mask; unsigned int ctreqcmp; unsigned short val; struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); int chan; chan = p - &ehrpwm->pwm[0]; if (!chan) { act_ctrl_reg = AQCTLA; cmp_reg = CMPA; ctreqcmp_mask = ACTCTL_CAU_MASK; ctreqcmp = 4; } else { act_ctrl_reg = AQCTLB; cmp_reg = CMPB; ctreqcmp_mask = ACTCTL_CBU_MASK; ctreqcmp = 8; } pm_runtime_get_sync(ehrpwm->dev); val = ((p->active_high ? ACTCTL_CTREQCMP_HIGH : ACTCTL_CTREQCMP_LOW) << ctreqcmp) | (p->active_high ? ACTCTL_CTREQZRO_LOW : ACTCTL_CTREQZRO_HIGH); ehrpwm_write(ehrpwm, act_ctrl_reg, val); pm_runtime_put_sync(ehrpwm->dev); return 0; }
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_set_phase(struct pwm_device *p, unsigned short val) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); ehrpwm_write(ehrpwm, TBPHS, val); 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; }
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; }
int ehrpwm_tb_force_sync(struct pwm_device *p) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); ehrpwm_reg_config(ehrpwm, TBCTL, ENABLE << TBCTL_FRC_SYC_POS, BIT(6)); 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; }
inline int ehrpwm_hr_set_cmpval(struct pwm_device *p, unsigned char val) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); ehrpwm_write(ehrpwm, CMPAHR, val << 8); return 0; }
inline int ehrpwm_et_clr_int(struct pwm_device *p) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); ehrpwm_write(ehrpwm, ETCLR, ENABLE); return 0; }
/* High Resolution Module configuration */ inline int ehrpwm_hr_set_phase(struct pwm_device *p, unsigned char val) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); ehrpwm_write(ehrpwm, TBPHSHR, val << 8); return 0; }
inline int ehrpwm_tz_clr_int_status(struct pwm_device *p) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); ehrpwm_write(ehrpwm, TZCLR, 0x1); return 0; }
inline int ehrpwm_et_int_en_dis(struct pwm_device *p, unsigned char en_dis) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); ehrpwm_reg_config(ehrpwm, ETSEL, en_dis << ETSEL_EN_INT_EN_POS, BIT(3)); return 0; }
static void ehrpwm_channel_output_low(struct pwm_device *p) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); int chan = p - &ehrpwm->pwm[0]; ehrpwm_aq_set_csfrc_load_mode(p, AQSFRC_RLDCSF_IMDT); ehrpwm_aq_continuous_frc(p, chan, AQCSFRC_CSF_FRCLOW); }
static void ehrpwm_channel_output_enable(struct pwm_device *p, int channel) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); pm_runtime_get_sync(ehrpwm->dev); ehrpwm_aq_set_csfrc_load_mode(p, AQSFRC_RLDCSF_ZRO); ehrpwm_aq_continuous_frc(p, channel, AQCSFRC_CSF_FRCDIS); pm_runtime_put_sync(ehrpwm->dev); }
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; }
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; }
int ehrpwm_tb_set_periodload(struct pwm_device *p, unsigned char loadmode) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (loadmode > 0x1) return -EINVAL; ehrpwm_reg_config(ehrpwm, TBCTL, loadmode << TBCTL_LOAD_MD_POS, BIT(3)); return 0; }
int ehrpwm_pc_en_dis(struct pwm_device *p, unsigned char chpen) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (chpen > 1) return -EINVAL; ehrpwm_reg_config(ehrpwm, PCCTL, chpen, BIT(0)); return 0; }
inline int ehrpwm_reg_write(struct pwm_device *p, unsigned int reg, unsigned short val) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (reg > HRCNFG) return -EINVAL; ehrpwm_write(ehrpwm, reg, 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 (reg > HRCNFG) return -EINVAL; *val = ehrpwm_read(ehrpwm, reg); return 0; }
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; }
int ehrpwm_aq_set_csfrc_load_mode(struct pwm_device *p, unsigned char loadmode) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (loadmode > 0x3) return -EINVAL; ehrpwm_reg_config(ehrpwm, AQSFRC, loadmode << AQSFRC_LDMD_POS, AQSFRC_CFRC_LOAD_MASK); return 0; }
/* Event Trigger Configuration functions */ int ehrpwm_et_set_sel_evt(struct pwm_device *p, unsigned char evt, unsigned char prd) { struct ehrpwm_pwm *ehrpwm = to_ehrpwm_pwm(p); if (evt > 0x7 || prd > 0x3) return -EINVAL; ehrpwm_reg_config(ehrpwm, ETSEL, evt, ETSEL_INTSEL_MASK); ehrpwm_reg_config(ehrpwm, ETPS, prd, ETPS_INTPRD_MASK); return 0; }