예제 #1
0
파일: c_can.c 프로젝트: 3null/linux
static void c_can_stop(struct net_device *dev)
{
	struct c_can_priv *priv = netdev_priv(dev);

	c_can_irq_control(priv, false);
	priv->can.state = CAN_STATE_STOPPED;
}
예제 #2
0
파일: c_can.c 프로젝트: Flipkart/linux
static int c_can_poll(struct napi_struct *napi, int quota)
{
	struct net_device *dev = napi->dev;
	struct c_can_priv *priv = netdev_priv(dev);
	u16 curr, last = priv->last_status;
	int work_done = 0;

	priv->last_status = curr = priv->read_reg(priv, C_CAN_STS_REG);
	/* Ack status on C_CAN. D_CAN is self clearing */
	if (priv->type != BOSCH_D_CAN)
		priv->write_reg(priv, C_CAN_STS_REG, LEC_UNUSED);

	/* handle state changes */
	if ((curr & STATUS_EWARN) && (!(last & STATUS_EWARN))) {
		netdev_dbg(dev, "entered error warning state\n");
		work_done += c_can_handle_state_change(dev, C_CAN_ERROR_WARNING);
	}

	if ((curr & STATUS_EPASS) && (!(last & STATUS_EPASS))) {
		netdev_dbg(dev, "entered error passive state\n");
		work_done += c_can_handle_state_change(dev, C_CAN_ERROR_PASSIVE);
	}

	if ((curr & STATUS_BOFF) && (!(last & STATUS_BOFF))) {
		netdev_dbg(dev, "entered bus off state\n");
		work_done += c_can_handle_state_change(dev, C_CAN_BUS_OFF);
		goto end;
	}

	/* handle bus recovery events */
	if ((!(curr & STATUS_BOFF)) && (last & STATUS_BOFF)) {
		netdev_dbg(dev, "left bus off state\n");
		priv->can.state = CAN_STATE_ERROR_ACTIVE;
	}
	if ((!(curr & STATUS_EPASS)) && (last & STATUS_EPASS)) {
		netdev_dbg(dev, "left error passive state\n");
		priv->can.state = CAN_STATE_ERROR_ACTIVE;
	}

	/* handle lec errors on the bus */
	work_done += c_can_handle_bus_err(dev, curr & LEC_MASK);

	/* Handle Tx/Rx events. We do this unconditionally */
	work_done += c_can_do_rx_poll(dev, (quota - work_done));
	c_can_do_tx(dev);

end:
	if (work_done < quota) {
		napi_complete(napi);
		/* enable all IRQs if we are not in bus off state */
		if (priv->can.state != CAN_STATE_BUS_OFF)
			c_can_irq_control(priv, true);
	}

	return work_done;
}
예제 #3
0
파일: c_can.c 프로젝트: Flipkart/linux
static void c_can_stop(struct net_device *dev)
{
	struct c_can_priv *priv = netdev_priv(dev);

	c_can_irq_control(priv, false);

	/* put ctrl to init on stop to end ongoing transmission */
	priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_INIT);

	/* deactivate pins */
	pinctrl_pm_select_sleep_state(dev->dev.parent);
	priv->can.state = CAN_STATE_STOPPED;
}
예제 #4
0
파일: c_can.c 프로젝트: Flipkart/linux
static irqreturn_t c_can_isr(int irq, void *dev_id)
{
	struct net_device *dev = (struct net_device *)dev_id;
	struct c_can_priv *priv = netdev_priv(dev);

	if (!priv->read_reg(priv, C_CAN_INT_REG))
		return IRQ_NONE;

	/* disable all interrupts and schedule the NAPI */
	c_can_irq_control(priv, false);
	napi_schedule(&priv->napi);

	return IRQ_HANDLED;
}
예제 #5
0
파일: c_can.c 프로젝트: Flipkart/linux
static int c_can_open(struct net_device *dev)
{
	int err;
	struct c_can_priv *priv = netdev_priv(dev);

	c_can_pm_runtime_get_sync(priv);
	c_can_reset_ram(priv, true);

	/* open the can device */
	err = open_candev(dev);
	if (err) {
		netdev_err(dev, "failed to open can device\n");
		goto exit_open_fail;
	}

	/* register interrupt handler */
	err = request_irq(dev->irq, &c_can_isr, IRQF_SHARED, dev->name,
				dev);
	if (err < 0) {
		netdev_err(dev, "failed to request interrupt\n");
		goto exit_irq_fail;
	}

	/* start the c_can controller */
	err = c_can_start(dev);
	if (err)
		goto exit_start_fail;

	can_led_event(dev, CAN_LED_EVENT_OPEN);

	napi_enable(&priv->napi);
	/* enable status change, error and module interrupts */
	c_can_irq_control(priv, true);
	netif_start_queue(dev);

	return 0;

exit_start_fail:
	free_irq(dev->irq, dev);
exit_irq_fail:
	close_candev(dev);
exit_open_fail:
	c_can_reset_ram(priv, false);
	c_can_pm_runtime_put_sync(priv);
	return err;
}
예제 #6
0
파일: c_can.c 프로젝트: Flipkart/linux
static int c_can_set_mode(struct net_device *dev, enum can_mode mode)
{
	struct c_can_priv *priv = netdev_priv(dev);
	int err;

	switch (mode) {
	case CAN_MODE_START:
		err = c_can_start(dev);
		if (err)
			return err;
		netif_wake_queue(dev);
		c_can_irq_control(priv, true);
		break;
	default:
		return -EOPNOTSUPP;
	}

	return 0;
}
예제 #7
0
파일: c_can.c 프로젝트: Flipkart/linux
int c_can_power_up(struct net_device *dev)
{
	u32 val;
	unsigned long time_out;
	struct c_can_priv *priv = netdev_priv(dev);
	int ret;

	if (!(dev->flags & IFF_UP))
		return 0;

	WARN_ON(priv->type != BOSCH_D_CAN);

	c_can_pm_runtime_get_sync(priv);
	c_can_reset_ram(priv, true);

	/* Clear PDR and INIT bits */
	val = priv->read_reg(priv, C_CAN_CTRL_EX_REG);
	val &= ~CONTROL_EX_PDR;
	priv->write_reg(priv, C_CAN_CTRL_EX_REG, val);
	val = priv->read_reg(priv, C_CAN_CTRL_REG);
	val &= ~CONTROL_INIT;
	priv->write_reg(priv, C_CAN_CTRL_REG, val);

	/* Wait for the PDA bit to get clear */
	time_out = jiffies + msecs_to_jiffies(INIT_WAIT_MS);
	while ((priv->read_reg(priv, C_CAN_STS_REG) & STATUS_PDA) &&
				time_after(time_out, jiffies))
		cpu_relax();

	if (time_after(jiffies, time_out))
		return -ETIMEDOUT;

	ret = c_can_start(dev);
	if (!ret)
		c_can_irq_control(priv, true);

	return ret;
}