예제 #1
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;
}
예제 #2
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #3
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #4
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #5
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #6
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #7
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #8
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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);
}
예제 #9
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #10
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #11
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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);
}
예제 #12
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;
}
예제 #13
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #14
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #15
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #16
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
/* 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;
}
예제 #17
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #18
0
파일: ehrpwm.c 프로젝트: BorisTw/BBB-kernel
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;
}
예제 #19
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;
}