diff options
Diffstat (limited to 'drivers/net/can/m_can/m_can.c')
| -rw-r--r-- | drivers/net/can/m_can/m_can.c | 66 | 
1 files changed, 38 insertions, 28 deletions
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c index e1d725979685..ad4f577c1ef7 100644 --- a/drivers/net/can/m_can/m_can.c +++ b/drivers/net/can/m_can/m_can.c @@ -1,7 +1,7 @@  // SPDX-License-Identifier: GPL-2.0  // CAN bus driver for Bosch M_CAN controller  // Copyright (C) 2014 Freescale Semiconductor, Inc. -//      Dong Aisheng <b29396@freescale.com> +//      Dong Aisheng <aisheng.dong@nxp.com>  // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/  /* Bosch M_CAN user manual can be obtained from: @@ -812,6 +812,9 @@ static int m_can_handle_state_change(struct net_device *dev,  	u32 timestamp = 0;  	switch (new_state) { +	case CAN_STATE_ERROR_ACTIVE: +		cdev->can.state = CAN_STATE_ERROR_ACTIVE; +		break;  	case CAN_STATE_ERROR_WARNING:  		/* error warning state */  		cdev->can.can_stats.error_warning++; @@ -841,6 +844,12 @@ static int m_can_handle_state_change(struct net_device *dev,  	__m_can_get_berr_counter(dev, &bec);  	switch (new_state) { +	case CAN_STATE_ERROR_ACTIVE: +		cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT; +		cf->data[1] = CAN_ERR_CRTL_ACTIVE; +		cf->data[6] = bec.txerr; +		cf->data[7] = bec.rxerr; +		break;  	case CAN_STATE_ERROR_WARNING:  		/* error warning state */  		cf->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT; @@ -877,30 +886,33 @@ static int m_can_handle_state_change(struct net_device *dev,  	return 1;  } -static int m_can_handle_state_errors(struct net_device *dev, u32 psr) +static enum can_state +m_can_state_get_by_psr(struct m_can_classdev *cdev)  { -	struct m_can_classdev *cdev = netdev_priv(dev); -	int work_done = 0; +	u32 reg_psr; -	if (psr & PSR_EW && cdev->can.state != CAN_STATE_ERROR_WARNING) { -		netdev_dbg(dev, "entered error warning state\n"); -		work_done += m_can_handle_state_change(dev, -						       CAN_STATE_ERROR_WARNING); -	} +	reg_psr = m_can_read(cdev, M_CAN_PSR); -	if (psr & PSR_EP && cdev->can.state != CAN_STATE_ERROR_PASSIVE) { -		netdev_dbg(dev, "entered error passive state\n"); -		work_done += m_can_handle_state_change(dev, -						       CAN_STATE_ERROR_PASSIVE); -	} +	if (reg_psr & PSR_BO) +		return CAN_STATE_BUS_OFF; +	if (reg_psr & PSR_EP) +		return CAN_STATE_ERROR_PASSIVE; +	if (reg_psr & PSR_EW) +		return CAN_STATE_ERROR_WARNING; -	if (psr & PSR_BO && cdev->can.state != CAN_STATE_BUS_OFF) { -		netdev_dbg(dev, "entered error bus off state\n"); -		work_done += m_can_handle_state_change(dev, -						       CAN_STATE_BUS_OFF); -	} +	return CAN_STATE_ERROR_ACTIVE; +} -	return work_done; +static int m_can_handle_state_errors(struct net_device *dev) +{ +	struct m_can_classdev *cdev = netdev_priv(dev); +	enum can_state new_state; + +	new_state = m_can_state_get_by_psr(cdev); +	if (new_state == cdev->can.state) +		return 0; + +	return m_can_handle_state_change(dev, new_state);  }  static void m_can_handle_other_err(struct net_device *dev, u32 irqstatus) @@ -1031,8 +1043,7 @@ static int m_can_rx_handler(struct net_device *dev, int quota, u32 irqstatus)  	}  	if (irqstatus & IR_ERR_STATE) -		work_done += m_can_handle_state_errors(dev, -						       m_can_read(cdev, M_CAN_PSR)); +		work_done += m_can_handle_state_errors(dev);  	if (irqstatus & IR_ERR_BUS_30X)  		work_done += m_can_handle_bus_errors(dev, irqstatus, @@ -1606,7 +1617,7 @@ static int m_can_start(struct net_device *dev)  	netdev_queue_set_dql_min_limit(netdev_get_tx_queue(cdev->net, 0),  				       cdev->tx_max_coalesced_frames); -	cdev->can.state = CAN_STATE_ERROR_ACTIVE; +	cdev->can.state = m_can_state_get_by_psr(cdev);  	m_can_enable_all_interrupts(cdev); @@ -2492,12 +2503,11 @@ int m_can_class_suspend(struct device *dev)  		}  		m_can_clk_stop(cdev); +		cdev->can.state = CAN_STATE_SLEEPING;  	}  	pinctrl_pm_select_sleep_state(dev); -	cdev->can.state = CAN_STATE_SLEEPING; -  	return ret;  }  EXPORT_SYMBOL_GPL(m_can_class_suspend); @@ -2510,8 +2520,6 @@ int m_can_class_resume(struct device *dev)  	pinctrl_pm_select_default_state(dev); -	cdev->can.state = CAN_STATE_ERROR_ACTIVE; -  	if (netif_running(ndev)) {  		ret = m_can_clk_start(cdev);  		if (ret) @@ -2529,6 +2537,8 @@ int m_can_class_resume(struct device *dev)  			if (cdev->ops->init)  				ret = cdev->ops->init(cdev); +			cdev->can.state = m_can_state_get_by_psr(cdev); +  			m_can_write(cdev, M_CAN_IE, cdev->active_interrupts);  		} else {  			ret  = m_can_start(ndev); @@ -2546,7 +2556,7 @@ int m_can_class_resume(struct device *dev)  }  EXPORT_SYMBOL_GPL(m_can_class_resume); -MODULE_AUTHOR("Dong Aisheng <b29396@freescale.com>"); +MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");  MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");  MODULE_LICENSE("GPL v2");  MODULE_DESCRIPTION("CAN bus driver for Bosch M_CAN controller");  | 
