Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756926Ab1BKOix (ORCPT ); Fri, 11 Feb 2011 09:38:53 -0500 Received: from mail-pz0-f46.google.com ([209.85.210.46]:50098 "EHLO mail-pz0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756724Ab1BKOit (ORCPT ); Fri, 11 Feb 2011 09:38:49 -0500 From: Subhasish Ghosh To: davinci-linux-open-source@linux.davincidsp.com Cc: linux-arm-kernel@lists.infradead.org, m-watkins@ti.com, nsekhar@ti.com, sachi@mistralsolutions.com, Subhasish Ghosh , Wolfgang Grandegger (maintainer:CAN NETWORK DRIVERS), socketcan-core@lists.berlios.de (open list:CAN NETWORK DRIVERS), netdev@vger.kernel.org (open list:CAN NETWORK DRIVERS), linux-kernel@vger.kernel.org (open list) Subject: [PATCH v2 09/13] can: pruss CAN driver. Date: Fri, 11 Feb 2011 20:21:28 +0530 Message-Id: <1297435892-28278-10-git-send-email-subhasish@mistralsolutions.com> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <1297435892-28278-1-git-send-email-subhasish@mistralsolutions.com> References: <1297435892-28278-1-git-send-email-subhasish@mistralsolutions.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 68295 Lines: 2435 This patch adds support for the CAN device emulated on PRUSS. Signed-off-by: Subhasish Ghosh --- drivers/net/can/Kconfig | 1 + drivers/net/can/Makefile | 1 + drivers/net/can/da8xx_pruss/Kconfig | 73 ++ drivers/net/can/da8xx_pruss/Makefile | 7 + drivers/net/can/da8xx_pruss/pruss_can.c | 758 +++++++++++++++++ drivers/net/can/da8xx_pruss/pruss_can_api.c | 1227 +++++++++++++++++++++++++++ drivers/net/can/da8xx_pruss/pruss_can_api.h | 290 +++++++ 7 files changed, 2357 insertions(+), 0 deletions(-) create mode 100644 drivers/net/can/da8xx_pruss/Kconfig create mode 100644 drivers/net/can/da8xx_pruss/Makefile create mode 100644 drivers/net/can/da8xx_pruss/pruss_can.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.c create mode 100644 drivers/net/can/da8xx_pruss/pruss_can_api.h diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index d5a9db6..ae8f0f9 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -112,6 +112,7 @@ config PCH_CAN This driver can access CAN bus. source "drivers/net/can/mscan/Kconfig" +source "drivers/net/can/da8xx_pruss/Kconfig" source "drivers/net/can/sja1000/Kconfig" diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index 07ca159..849cdbf 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000/ obj-$(CONFIG_CAN_MSCAN) += mscan/ obj-$(CONFIG_CAN_AT91) += at91_can.o obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o +obj-$(CONFIG_CAN_TI_DA8XX_PRU) += da8xx_pruss/ obj-$(CONFIG_CAN_MCP251X) += mcp251x.o obj-$(CONFIG_CAN_BFIN) += bfin_can.o obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o diff --git a/drivers/net/can/da8xx_pruss/Kconfig b/drivers/net/can/da8xx_pruss/Kconfig new file mode 100644 index 0000000..8b68f68 --- /dev/null +++ b/drivers/net/can/da8xx_pruss/Kconfig @@ -0,0 +1,73 @@ +# +# CAN Lite Kernel Configuration +# +config CAN_TI_DA8XX_PRU + depends on CAN_DEV && ARCH_DAVINCI && ARCH_DAVINCI_DA850 + tristate "PRU based CAN emulation for DA8XX" + ---help--- + Enable this to emulate a CAN controller on the PRU of DA8XX. + If not sure, mark N + +config DA8XX_PRU_CANID_MBX0 + hex "CANID for mailbox 0" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 0 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX1 + hex "CANID for mailbox 1" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 1 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX2 + hex "CANID for mailbox 2" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 2 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX3 + hex "CANID for mailbox 3" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 3 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX4 + hex "CANID for mailbox 4" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 4 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX5 + hex "CANID for mailbox 5" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 5 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX6 + hex "CANID for mailbox 6" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 6 + Default value is set to 0x123, change this as required. + +config DA8XX_PRU_CANID_MBX7 + hex "CANID for mailbox 7" + depends on CAN_TI_DA8XX_PRU + default "0x123" + ---help--- + Enter the CANID for mailbox 7 + Default value is set to 0x123, change this as required. diff --git a/drivers/net/can/da8xx_pruss/Makefile b/drivers/net/can/da8xx_pruss/Makefile new file mode 100644 index 0000000..48f3055 --- /dev/null +++ b/drivers/net/can/da8xx_pruss/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for CAN Lite emulation +# +can_emu-objs := pruss_can.o \ + pruss_can_api.o + +obj-$(CONFIG_CAN_TI_DA8XX_PRU) += can_emu.o diff --git a/drivers/net/can/da8xx_pruss/pruss_can.c b/drivers/net/can/da8xx_pruss/pruss_can.c new file mode 100644 index 0000000..1b3afde --- /dev/null +++ b/drivers/net/can/da8xx_pruss/pruss_can.c @@ -0,0 +1,758 @@ +/* + * TI DA8XX PRU CAN Emulation device driver + * Author: subhasish@mistralsolutions.com + * + * This driver supports TI's PRU CAN Emulation and the + * specs for the same is available at + * + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed as is WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "pruss_can_api.h" + +#define DRV_NAME "da8xx_pruss_can" +#define DRV_DESC "TI PRU CAN Controller Driver v0.1" +#define PRU_CAN_START 1 +#define PRU_CAN_STOP 0 +#define MB_MIN 0 +#define MB_MAX 7 + +#define PRU_CANMID_IDE BIT(29) /* Extended frame format */ + +#define PRU_CAN_ISR_BIT_CCI BIT(15) +#define PRU_CAN_ISR_BIT_ESI BIT(14) +#define PRU_CAN_ISR_BIT_SRDI BIT(13) +#define PRU_CAN_ISR_BIT_RRI BIT(8) + +#define PRU_CAN_MBXSR_BIT_STATE BIT(7) +#define PRU_CAN_MBXSR_BIT_TC BIT(6) +#define PRU_CAN_MBXSR_BIT_ERR BIT(5) +#define PRU_CAN_MBXSR_BIT_OF BIT(0) + +#define PRU_CAN_GSR_BIT_TXM BIT(7) +#define PRU_CAN_GSR_BIT_RXM BIT(6) +#define PRU_CAN_GSR_BIT_CM BIT(5) +#define PRU_CAN_GSR_BIT_EPM BIT(4) +#define PRU_CAN_GSR_BIT_BFM BIT(3) +#define RTR_MBX_NO 8 +#define MAX_INIT_RETRIES 20 +#define L138_PRU_ARM_FREQ 312000 +#define DFLT_PRU_FREQ 156000000 +#define DFLT_PRU_BITRATE 125000 + +#define CONFIG_DA8XX_PRU_CANID_MBX0 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX1 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX2 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX3 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX4 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX5 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX6 0x123 +#define CONFIG_DA8XX_PRU_CANID_MBX7 0x123 + +#ifdef __CAN_DEBUG +#define __can_debug(fmt, args...) printk(KERN_DEBUG "can_debug: " fmt, ## args) +#else +#define __can_debug(fmt, args...) +#endif +#define __can_err(fmt, args...) printk(KERN_ERR "can_err: " fmt, ## args) + +/* + * omapl_pru can private data + */ +struct omapl_pru_can_priv { + struct can_priv can; + struct workqueue_struct *pru_can_wQ; + struct work_struct rx_work; + struct net_device *ndev; + struct device *dev; /* pdev->dev */ + struct clk *clk_timer; + u32 timer_freq; + can_emu_app_hndl can_tx_hndl; + can_emu_app_hndl can_rx_hndl; + const struct firmware *fw_rx; + const struct firmware *fw_tx; + spinlock_t mbox_lock; + u32 trx_irq; + u32 tx_head; + u32 tx_tail; + u32 tx_next; + u32 rx_next; +}; + +static int omapl_pru_can_get_state(const struct net_device *ndev, + enum can_state *state) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + *state = priv->can.state; + return 0; +} + +static int omapl_pru_can_set_bittiming(struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + struct can_bittiming *bt = &priv->can.bittiming; + long bit_error = 0; + + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) { + dev_warn(priv->dev, "WARN: Triple" + "sampling not set due to h/w limitations"); + } + if (pru_can_calc_timing(priv->dev, priv->can.clock.freq, + bt->bitrate) != 0) + return -EINVAL; + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) * 1000) / bt->bitrate; + if (bit_error) { + bit_error = + (((priv->timer_freq / (priv->timer_freq / bt->bitrate)) - + bt->bitrate) * 1000000) / bt->bitrate; + printk(KERN_INFO "\nBitrate error %ld.%ld%%\n", + bit_error / 10000, bit_error % 1000); + } else + printk(KERN_INFO "\nBitrate error 0.0%%\n"); + + return 0; +} + +static void omapl_pru_can_stop(struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + u16 int_mask = 0; + + pru_can_mask_ints(priv->dev, int_mask); /* mask all ints */ + pru_can_start_abort_tx(priv->dev, PRU_CAN_STOP); + priv->can.state = CAN_STATE_STOPPED; +} + +/* + * This is to just set the can state to ERROR_ACTIVE + * ip link set canX up type can bitrate 125000 + */ +static void omapl_pru_can_start(struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + u16 int_mask = 0xFFFF; + + if (priv->can.state != CAN_STATE_STOPPED) + omapl_pru_can_stop(ndev); + + pru_can_mask_ints(priv->dev, int_mask); /* unmask all ints */ + + pru_can_get_global_status(priv->dev, &priv->can_tx_hndl); + pru_can_get_global_status(priv->dev, &priv->can_rx_hndl); + + if (PRU_CAN_GSR_BIT_EPM & priv->can_tx_hndl.u32globalstatus) + priv->can.state = CAN_STATE_ERROR_PASSIVE; + else if (PRU_CAN_GSR_BIT_BFM & priv->can_tx_hndl.u32globalstatus) + priv->can.state = CAN_STATE_BUS_OFF; + else + priv->can.state = CAN_STATE_ERROR_ACTIVE; +} + +static int omapl_pru_can_set_mode(struct net_device *ndev, enum can_mode mode) +{ + int ret = 0; + + switch (mode) { + case CAN_MODE_START: + omapl_pru_can_start(ndev); + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + break; + case CAN_MODE_STOP: + omapl_pru_can_stop(ndev); + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); + break; + default: + ret = -EOPNOTSUPP; + break; + } + return ret; +} + +static netdev_tx_t omapl_pru_can_start_xmit(struct sk_buff *skb, + struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + struct can_frame *cf = (struct can_frame *)skb->data; + int count; + u8 *data = cf->data; + u8 dlc = cf->can_dlc; + u8 *ptr8data = NULL; + + netif_stop_queue(ndev); + if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id & CAN_EFF_MASK) | PRU_CANMID_IDE; + else /* Standard frame format */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) = + (cf->can_id & CAN_SFF_MASK) << 18; + + if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */ + *((u32 *) &priv->can_tx_hndl.strcanmailbox) |= CAN_RTR_FLAG; + + ptr8data = &priv->can_tx_hndl.strcanmailbox.u8data7 + (dlc - 1); + for (count = 0; count < (u8) dlc; count++) { + *ptr8data-- = *data++; + } + *((u32 *) &priv->can_tx_hndl.strcanmailbox.u16datalength) = (u32) dlc; +/* + * search for the next available mbx + * if the next mbx is busy, then try the next + 1 + * do this until the head is reached. + * if still unable to tx, stop accepting any packets + * if able to tx and the head is reached, then reset next to tail, i.e mbx0 + * if head is not reached, then just point to the next mbx + */ + for (; priv->tx_next <= priv->tx_head; priv->tx_next++) { + priv->can_tx_hndl.ecanmailboxnumber = + (can_mailbox_number) priv->tx_next; + if (-1 == pru_can_write_data_to_mailbox(priv->dev, + &priv->can_tx_hndl)) { + if (priv->tx_next == priv->tx_head) { + priv->tx_next = priv->tx_tail; + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); /* IF stalled */ + dev_err(priv->dev, + "%s: no tx mbx available", __func__); + return NETDEV_TX_BUSY; + } else + continue; + } else { + /* set transmit request */ + pru_can_tx(priv->dev, priv->tx_next, CAN_TX_PRU_1); + pru_can_tx_mode_set(priv->dev, false, ecanreceive); + pru_can_tx_mode_set(priv->dev, true, ecantransmit); + pru_can_start_abort_tx(priv->dev, PRU_CAN_START); + priv->tx_next++; + can_put_echo_skb(skb, ndev, 0); + break; + } + } + if (priv->tx_next > priv->tx_head) { + priv->tx_next = priv->tx_tail; + } + return NETDEV_TX_OK; +} + +static int omapl_pru_can_rx(struct net_device *ndev, u32 mbxno) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + u32 pru_can_mbx_data; + u8 *data = NULL; + u8 *ptr8data = NULL; + int count = 0; + + skb = alloc_can_skb(ndev, &cf); + if (!skb) { + if (printk_ratelimit()) + dev_err(priv->dev, + "alloc_can_skb() failed\n"); + return -ENOMEM; + } + data = cf->data; + /* get payload */ + priv->can_rx_hndl.ecanmailboxnumber = (can_mailbox_number) mbxno; + if (pru_can_get_data_from_mailbox(priv->dev, &priv->can_rx_hndl)) { + __can_err("failed to get data from mailbox\n"); + return -EAGAIN; + } + /* give ownweship to pru */ + pru_can_tx(priv->dev, mbxno, CAN_RX_PRU_0); + + /* get data length code */ + cf->can_dlc = + get_can_dlc(* + ((u32 *) &priv->can_rx_hndl.strcanmailbox. + u16datalength) & 0xF); + if (cf->can_dlc <= 4) { + ptr8data = + &priv->can_rx_hndl.strcanmailbox.u8data3 + (4 - + cf->can_dlc); + for (count = 0; count < cf->can_dlc; count++) { + *data++ = *ptr8data++; + } + } else { + ptr8data = &priv->can_rx_hndl.strcanmailbox.u8data3; + for (count = 0; count < 4; count++) { + *data++ = *ptr8data++; + } + ptr8data = + &priv->can_rx_hndl.strcanmailbox.u8data4 - (cf->can_dlc - + 5); + for (count = 0; count < cf->can_dlc - 4; count++) { + *data++ = *ptr8data++; + } + } + + pru_can_mbx_data = *((u32 *) &priv->can_rx_hndl.strcanmailbox); + /* get id extended or std */ + if (pru_can_mbx_data & PRU_CANMID_IDE) + cf->can_id = (pru_can_mbx_data & CAN_EFF_MASK) | CAN_EFF_FLAG; + else + cf->can_id = (pru_can_mbx_data >> 18) & CAN_SFF_MASK; + + if (pru_can_mbx_data & CAN_RTR_FLAG) + cf->can_id |= CAN_RTR_FLAG; + + netif_rx_ni(skb); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + return 0; +} + +static int omapl_pru_can_err(struct net_device *ndev, int int_status, + int err_status) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + struct can_frame *cf; + struct sk_buff *skb; + int tx_err_cnt, rx_err_cnt; + + /* propogate the error condition to the can stack */ + skb = alloc_can_err_skb(ndev, &cf); + if (!skb) { + if (printk_ratelimit()) + dev_err(priv->dev, + "alloc_can_err_skb() failed\n"); + return -ENOMEM; + } + + if (err_status & PRU_CAN_GSR_BIT_EPM) { /* error passive int */ + priv->can.state = CAN_STATE_ERROR_PASSIVE; + ++priv->can.can_stats.error_passive; + cf->can_id |= CAN_ERR_CRTL; + tx_err_cnt = pru_can_get_error_cnt(priv->dev, CAN_TX_PRU_1); + rx_err_cnt = pru_can_get_error_cnt(priv->dev, CAN_RX_PRU_0); + if (tx_err_cnt > 127) + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE; + if (rx_err_cnt > 127) + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE; + + dev_dbg(priv->ndev->dev.parent, "Error passive interrupt\n"); + } + + if (err_status & PRU_CAN_GSR_BIT_BFM) { + priv->can.state = CAN_STATE_BUS_OFF; + cf->can_id |= CAN_ERR_BUSOFF; + /* + * Disable all interrupts in bus-off to avoid int hog + * this should be handled by the pru + */ + pru_can_mask_ints(priv->dev, 0xFFFF); + can_bus_off(ndev); + dev_dbg(priv->ndev->dev.parent, "Bus off mode\n"); + } + + netif_rx(skb); + stats->rx_packets++; + stats->rx_bytes += cf->can_dlc; + return 0; +} + +void omapl_pru_can_rx_wQ(struct work_struct *work) +{ + struct omapl_pru_can_priv *priv = container_of(work, + struct omapl_pru_can_priv, rx_work); + struct net_device *ndev = priv->ndev; + u32 bit_set, mbxno = 0; + + if (-1 == pru_can_get_intr_status(priv->dev, &priv->can_rx_hndl)) + return; + + if (PRU_CAN_ISR_BIT_RRI & priv->can_rx_hndl.u32interruptstatus) { + mbxno = RTR_MBX_NO; + omapl_pru_can_rx(ndev, mbxno); + } else { + /* Extract the mboxno from the status */ + for (bit_set = 0; ((priv->can_rx_hndl.u32interruptstatus & 0xFF) + >> bit_set != 0); bit_set++) + ; + if (0 == bit_set) { + dev_err(priv->dev, + "%s: invalid mailbox number: %X\n", __func__, + priv->can_rx_hndl.u32interruptstatus); + } else { + mbxno = bit_set - 1; + if (PRU_CAN_ISR_BIT_ESI & priv->can_rx_hndl. + u32interruptstatus) { + pru_can_get_global_status(priv->dev, + &priv->can_rx_hndl); + omapl_pru_can_err(ndev, + priv->can_rx_hndl.u32interruptstatus, + priv->can_rx_hndl.u32globalstatus); + } else { + omapl_pru_can_rx(ndev, mbxno); + } + } + } +} + +irqreturn_t omapl_tx_can_intr(int irq, void *dev_id) +{ + struct net_device *ndev = dev_id; + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; + u32 bit_set, mbxno; + + pru_can_get_intr_status(priv->dev, &priv->can_tx_hndl); + if ((PRU_CAN_ISR_BIT_CCI & priv->can_tx_hndl.u32interruptstatus) + || (PRU_CAN_ISR_BIT_SRDI & priv->can_tx_hndl.u32interruptstatus)) { + __can_debug("tx_int_status = 0x%X\n", + priv->can_tx_hndl.u32interruptstatus); + can_free_echo_skb(ndev, 0); + } else { + for (bit_set = 0; ((priv->can_tx_hndl.u32interruptstatus & 0xFF) + >> bit_set != 0); bit_set++) + ; + if (0 == bit_set) { + __can_err("%s: invalid mailbox number\n", __func__); + can_free_echo_skb(ndev, 0); + } else { + mbxno = bit_set - 1; /* mail box numbering starts from 0 */ + if (PRU_CAN_ISR_BIT_ESI & priv->can_tx_hndl. + u32interruptstatus) { + /* read gsr and ack pru */ + pru_can_get_global_status(priv->dev, &priv->can_tx_hndl); + omapl_pru_can_err(ndev, + priv->can_tx_hndl. + u32interruptstatus, + priv->can_tx_hndl. + u32globalstatus); + } else { + stats->tx_packets++; + /* stats->tx_bytes += dlc; */ + /*can_get_echo_skb(ndev, 0);*/ + } + } + } + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + + can_get_echo_skb(ndev, 0); + pru_can_tx_mode_set(priv->dev, true, ecanreceive); + return IRQ_HANDLED; +} + +irqreturn_t omapl_rx_can_intr(int irq, void *dev_id) +{ + + struct net_device *ndev = dev_id; + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + u32 intc_status = 0; + + intc_status = pru_can_get_intc_status(priv->dev); + if (intc_status & 4) + return omapl_tx_can_intr(irq, dev_id); + if (intc_status & 2) { + if (!work_pending(&priv->rx_work)) + queue_work(priv->pru_can_wQ, &priv->rx_work); + } + + return IRQ_HANDLED; +} + +static int omapl_pru_can_open(struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + int err; + + /* register interrupt handler */ + err = request_irq(priv->trx_irq, &omapl_rx_can_intr, IRQF_SHARED, + "pru_can_irq", ndev); + if (err) { + dev_err(priv->dev, "error requesting rx interrupt\n"); + goto exit_trx_irq; + } + /* common open */ + err = open_candev(ndev); + if (err) { + dev_err(priv->dev, "open_candev() failed %d\n", err); + goto exit_open; + } + + pru_can_emu_init(priv->dev, priv->can.clock.freq); + priv->tx_tail = MB_MIN; + priv->tx_head = MB_MAX; + + pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX0, 0); + pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX1, 1); + pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX2, 2); + pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX3, 3); + pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX4, 4); + pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX5, 5); + pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX6, 6); + pru_can_rx_id_map(priv->dev, CONFIG_DA8XX_PRU_CANID_MBX7, 7); + + omapl_pru_can_start(ndev); + netif_start_queue(ndev); + return 0; + +exit_open: + free_irq(priv->trx_irq, ndev); +exit_trx_irq: + return err; +} + +static int omapl_pru_can_close(struct net_device *ndev) +{ + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + + if (!netif_queue_stopped(ndev)) + netif_stop_queue(ndev); + + close_candev(ndev); + + free_irq(priv->trx_irq, ndev); + return 0; +} + +static const struct net_device_ops omapl_pru_can_netdev_ops = { + .ndo_open = omapl_pru_can_open, + .ndo_stop = omapl_pru_can_close, + .ndo_start_xmit = omapl_pru_can_start_xmit, +}; + +static int __devinit omapl_pru_can_probe(struct platform_device *pdev) +{ + struct net_device *ndev = NULL; + const struct da8xx_pru_can_data *pdata; + struct omapl_pru_can_priv *priv = NULL; + struct device *dev = &pdev->dev; + u32 err; + + pdata = dev->platform_data; + if (!pdata) { + dev_err(&pdev->dev, "platform data not found\n"); + return -EINVAL; + } + + ndev = alloc_candev(sizeof(struct omapl_pru_can_priv), MB_MAX + 1); + if (!ndev) { + dev_err(&pdev->dev, "alloc_candev failed\n"); + err = -ENOMEM; + goto probe_exit; + } + priv = netdev_priv(ndev); + + priv->trx_irq = platform_get_irq(to_platform_device(dev->parent), 0); + if (!priv->trx_irq) { + dev_err(&pdev->dev, "unable to get pru interrupt resources!\n"); + err = -ENODEV; + goto probe_exit; + } + + priv->ndev = ndev; + priv->dev = dev; /* priv->dev = pdev->dev */ + + priv->can.bittiming_const = NULL; + priv->can.do_set_bittiming = omapl_pru_can_set_bittiming; + priv->can.do_set_mode = omapl_pru_can_set_mode; + priv->can.do_get_state = omapl_pru_can_get_state; + priv->can_tx_hndl.u8prunumber = CAN_TX_PRU_1; + priv->can_rx_hndl.u8prunumber = CAN_RX_PRU_0; + + /* we support local echo, no arp */ + ndev->flags |= (IFF_ECHO | IFF_NOARP); + + /* pdev->dev->device_private->driver_data = ndev */ + platform_set_drvdata(pdev, ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); + ndev->netdev_ops = &omapl_pru_can_netdev_ops; + + priv->can.clock.freq = pruss_get_clk_freq(priv->dev); + + priv->clk_timer = clk_get(&pdev->dev, "pll1_sysclk2"); + if (IS_ERR(priv->clk_timer)) { + dev_err(&pdev->dev, "no timer clock available\n"); + err = PTR_ERR(priv->clk_timer); + priv->clk_timer = NULL; + goto probe_exit_candev; + } + priv->timer_freq = clk_get_rate(priv->clk_timer); + + err = register_candev(ndev); + if (err) { + dev_err(&pdev->dev, "register_candev() failed\n"); + err = -ENODEV; + goto probe_exit_clk; + } + + err = request_firmware(&priv->fw_tx, "PRU_CAN_Emulation_Tx.bin", + &pdev->dev); + if (err) { + dev_err(&pdev->dev, "can't load firmware\n"); + err = -ENODEV; + goto probe_exit_clk; + } + + dev_info(&pdev->dev, "fw_tx size %d. downloading...\n", + priv->fw_tx->size); + + err = request_firmware(&priv->fw_rx, "PRU_CAN_Emulation_Rx.bin", + &pdev->dev); + if (err) { + dev_err(&pdev->dev, "can't load firmware\n"); + err = -ENODEV; + goto probe_release_fw; + } + dev_info(&pdev->dev, "fw_rx size %d. downloading...\n", + priv->fw_rx->size); + + /* init the pru */ + pru_can_emu_init(priv->dev, priv->can.clock.freq); + udelay(200); + + pruss_enable(priv->dev, CAN_RX_PRU_0); + pruss_enable(priv->dev, CAN_TX_PRU_1); + + /* download firmware into pru */ + err = pruss_load(priv->dev, CAN_RX_PRU_0, + (u32 *)priv->fw_rx->data, (priv->fw_rx->size / 4)); + if (err) { + dev_err(&pdev->dev, "firmware download error\n"); + err = -ENODEV; + goto probe_release_fw_1; + } + err = pruss_load(priv->dev, CAN_TX_PRU_1, + (u32 *)priv->fw_tx->data, (priv->fw_tx->size / 4)); + if (err) { + dev_err(&pdev->dev, "firmware download error\n"); + err = -ENODEV; + goto probe_release_fw_1; + } + + if (pru_can_calc_timing(priv->dev, DFLT_PRU_FREQ, + DFLT_PRU_BITRATE) != 0) + return -EINVAL; + + pruss_run(priv->dev, CAN_RX_PRU_0); + pruss_run(priv->dev, CAN_TX_PRU_1); + + /*Create The Work Queue */ + priv->pru_can_wQ = create_freezeable_workqueue("omapl_pru_wQ"); + if (priv->pru_can_wQ == NULL) { + dev_err(&pdev->dev, "failed to create work queue\n"); + err = -ENODEV; + goto probe_release_fw_1; + } + + INIT_WORK(&priv->rx_work, omapl_pru_can_rx_wQ); + dev_info(&pdev->dev, + "%s device registered (trx_irq = %d, clk = %d)\n", + DRV_NAME, priv->trx_irq, priv->can.clock.freq); + + return 0; + +probe_release_fw_1: + release_firmware(priv->fw_rx); +probe_release_fw: + release_firmware(priv->fw_tx); +probe_exit_clk: + clk_put(priv->clk_timer); +probe_exit_candev: + if (NULL != ndev) + free_candev(ndev); +probe_exit: + return err; +} + +static int __devexit omapl_pru_can_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct omapl_pru_can_priv *priv = netdev_priv(ndev); + + omapl_pru_can_stop(ndev); + + pru_can_emu_exit(priv->dev); + release_firmware(priv->fw_tx); + release_firmware(priv->fw_rx); + clk_put(priv->clk_timer); + flush_workqueue(priv->pru_can_wQ); + destroy_workqueue(priv->pru_can_wQ); + unregister_candev(ndev); + free_candev(ndev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +#ifdef CONFIG_PM +static int omapl_pru_can_suspend(struct platform_device *pdev, + pm_message_t mesg) +{ + dev_info(&pdev->dev, "%s not yet implemented\n", __func__); + return 0; +} + +static int omapl_pru_can_resume(struct platform_device *pdev) +{ + dev_info(&pdev->dev, "%s not yet implemented\n", __func__); + return 0; +} +#else +#define omapl_pru_can_suspend NULL +#define omapl_pru_can_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver omapl_pru_can_driver = { + .probe = omapl_pru_can_probe, + .remove = __devexit_p(omapl_pru_can_remove), + .suspend = omapl_pru_can_suspend, + .resume = omapl_pru_can_resume, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init omapl_pru_can_init(void) +{ + __can_debug(KERN_INFO DRV_DESC "\n"); + return platform_driver_register(&omapl_pru_can_driver); +} + +module_init(omapl_pru_can_init); + +static void __exit omapl_pru_can_exit(void) +{ + __can_debug(KERN_INFO DRV_DESC " unloaded\n"); + platform_driver_unregister(&omapl_pru_can_driver); +} + +module_exit(omapl_pru_can_exit); + +MODULE_AUTHOR("Subhasish Ghosh "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("omapl pru CAN netdevice driver"); diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.c b/drivers/net/can/da8xx_pruss/pruss_can_api.c new file mode 100644 index 0000000..2f7438a --- /dev/null +++ b/drivers/net/can/da8xx_pruss/pruss_can_api.c @@ -0,0 +1,1227 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Wilfred Felix + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include "pruss_can_api.h" + +static can_emu_drv_inst gstr_can_inst[ecanmaxinst]; + +/* + * pru_can_set_brp() Updates the BRP register of PRU0 + * and PRU1 of OMAP L138. This API will be called by the + * Application to updtae the BRP register of PRU0 and PRU1 + * + * param u16bitrateprescaler The can bus bitrate + * prescaler value be set + * + * return SUCCESS or FAILURE + */ +s16 pru_can_set_brp(struct device *dev, u16 u16bitrateprescaler) +{ + + u32 u32offset; + + if (u16bitrateprescaler > 255) { + return -1; + } + + u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER); + pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1); + + u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER); + pruss_writel(dev, u32offset, (u32 *) &u16bitrateprescaler, 1); + + return 0; + +} + +/* + * pru_can_set_bit_timing() Updates the timing register + * of PRU0 and PRU1 of OMAP L138. This API will be called by + * the Application to updtae the timing register of PRU0 and PRU1 + * + * param pstrbittiming Pointer to structure holding + * the bit timing values for can bus. + * + * return SUCCESS or FAILURE + */ +s16 pru_can_set_bit_timing(struct device *dev, + can_bit_timing_consts *pstrbittiming) +{ + + u32 u32offset; + u32 u32serregister; + + u32serregister = 0; + + if (pstrbittiming == NULL) { + return -1; + } + + if ((pstrbittiming->u8syncjumpwidth > PRU_CAN_MAX_SJW) || + (pstrbittiming->u8phseg1 > PRU_CAN_MAX_PHSEG1) || + (pstrbittiming->u8phseg2 > PRU_CAN_MAX_PHSEG2)) { + return -1; + } + + u32serregister = u32serregister | + ((pstrbittiming->u8syncjumpwidth << 7) | + (pstrbittiming->u8phseg1 << 3) | + (pstrbittiming->u8phseg2)); + + u32offset = (PRU_CAN_TX_TIMING_REGISTER); + pruss_writel(dev, u32offset, (u32 *) &u32serregister, 1); + + u32offset = (PRU_CAN_RX_TIMING_REGISTER); + pruss_writel(dev, u32offset, (u32 *) &u32serregister, 1); + + return 0; +} + + +/* + * pru_can_calc_timing() + * Updates the timing values of PRU0 and PRU1 of OMAP L138. + * This API will be called by the + * Application to updtae the timing values of PRU0 and PRU1 + * + * return SUCCESS or FAILURE + */ + +s16 pru_can_calc_timing(struct device *dev, u32 pru_freq, u32 bit_rate) +{ + u16 u16phaseseg1; + u16 u16phaseseg2; + u32 u32offset; + u32 u32timing_value; + u32 u32setup_value; + u32timing_value = TIMER_CLK_FREQ / bit_rate; + u32offset = (PRU_CAN_TIMING_VAL_TX); + pruss_writel(dev, u32offset, (u32 *) &u32timing_value, 4); + pruss_readl(dev, u32offset, (u32 *) &u32timing_value, 4); + u32setup_value = + (GPIO_SETUP_DELAY * (pru_freq / 1000000) / 1000) / + DELAY_LOOP_LENGTH; + u32offset = (PRU_CAN_TIMING_VAL_TX_SJW); + pruss_writel(dev, u32offset, (u32 *) &u32setup_value, 4); + u16phaseseg1 = (u16) (u32timing_value / 2); + u16phaseseg2 = u32timing_value - u16phaseseg1; + u16phaseseg1 -= TIMER_SETUP_DELAY; + u16phaseseg2 -= TIMER_SETUP_DELAY; + u32setup_value = (u16phaseseg1 << 16) | u16phaseseg2; + u32offset = (PRU_CAN_TIMING_VAL_RX); + pruss_writel(dev, u32offset, (u32 *) &u32setup_value, 4); + u32offset = (PRU_CAN_TIMING_VAL_RX + 4); + pruss_writel(dev, u32offset, (u32 *) &u32timing_value, 4); + + return 0; +} + +/* + * pru_can_write_data_to_mailbox() + * Updates the transmit mailboxes of PRU1 of OMAP L138. + * This API will be called by the Application to update + * the transmit mailboxes of PRU1 + * + * param pu16canframedata Can mailbox data buffer + * + * param u8mailboxnum Mailbox to be updated + * + * return SUCCESS or FAILURE + */ +s16 pru_can_write_data_to_mailbox(struct device *dev, + can_emu_app_hndl *pstremuapphndl) +{ + s16 s16subrtnretval; + u32 u32offset; + + if (pstremuapphndl == NULL) { + return -1; + } + + switch ((u8) pstremuapphndl->ecanmailboxnumber) { + case 0: + u32offset = (PRU_CAN_TX_MAILBOX0); + break; + case 1: + u32offset = (PRU_CAN_TX_MAILBOX1); + break; + case 2: + u32offset = (PRU_CAN_TX_MAILBOX2); + break; + case 3: + u32offset = (PRU_CAN_TX_MAILBOX3); + break; + case 4: + u32offset = (PRU_CAN_TX_MAILBOX4); + break; + case 5: + u32offset = (PRU_CAN_TX_MAILBOX5); + break; + case 6: + u32offset = (PRU_CAN_TX_MAILBOX6); + break; + case 7: + u32offset = (PRU_CAN_TX_MAILBOX7); + break; + default: + return -1; + } + + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &(pstremuapphndl->strcanmailbox), 4); + if (s16subrtnretval == -1) { + return -1; + } + return 0; +} + +/* + * pru_can_get_data_from_mailbox() + * Receive data from the receive mailboxes of PRU0 of OMAP L138. + * This API will be called by the Application to get data from + * the receive mailboxes of PRU0 + * + * param pu16canframedata Can mailbox data buffer + * + * param u8mailboxnum Mailbox to be updated + * + * return SUCCESS or FAILURE + */ +s16 pru_can_get_data_from_mailbox(struct device *dev, + can_emu_app_hndl *pstremuapphndl) +{ + s16 s16subrtnretval; + u32 u32offset; + + if (pstremuapphndl == NULL) { + return -1; + } + + switch ((u8) pstremuapphndl->ecanmailboxnumber) { + case 0: + u32offset = (PRU_CAN_RX_MAILBOX0); + break; + case 1: + u32offset = (PRU_CAN_RX_MAILBOX1); + break; + case 2: + u32offset = (PRU_CAN_RX_MAILBOX2); + break; + case 3: + u32offset = (PRU_CAN_RX_MAILBOX3); + break; + case 4: + u32offset = (PRU_CAN_RX_MAILBOX4); + break; + case 5: + u32offset = (PRU_CAN_RX_MAILBOX5); + break; + case 6: + u32offset = (PRU_CAN_RX_MAILBOX6); + break; + case 7: + u32offset = (PRU_CAN_RX_MAILBOX7); + break; + case 8: + u32offset = (PRU_CAN_RX_MAILBOX8); + break; + default: + return -1; + } + + s16subrtnretval = + pruss_readl(dev, u32offset, + (u32 *) &(pstremuapphndl->strcanmailbox), + 4); + if (s16subrtnretval == -1) { + return -1; + } + return 0; +} + +/* + * pru_can_receive_id_map() + * Receive mailboxes ID Mapping of PRU0 of OMAP L138. + * This API will be called by the Application + * to map the IDs to receive mailboxes of PRU0 + * + * param u32nodeid Can node ID + * + * param ecanmailboxno Mailbox to be mapped + * + * return SUCCESS or FAILURE + */ +s16 pru_can_rx_id_map(struct device *dev, u32 u32nodeid, + can_mailbox_number ecanmailboxno) +{ + + pruss_writel(dev, (PRU_CAN_ID_MAP + + (((u8) ecanmailboxno) * 4)), (u32 *) &u32nodeid, 1); + + return 0; +} + +/* + * pru_can_get_intr_status() + * Gets the interrupts status register value. + * This API will be called by the Application + * to get the interrupts status register value + * + * param u8prunumber PRU number for which IntStatusReg + * has to be read + * + * return SUCCESS or FAILURE + */ +s16 pru_can_get_intr_status(struct device *dev, + can_emu_app_hndl *pstremuapphndl) +{ + u32 u32offset; + s16 s16subrtnretval = -1; + + if (pstremuapphndl == NULL) { + return -1; + } + + if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) { + u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER); + } else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) { + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER); + } else { + return -1; + } + + s16subrtnretval = pruss_readl(dev, u32offset, + (u32 *) &pstremuapphndl->u32interruptstatus, 1); + if (s16subrtnretval == -1) { + return -1; + } + + return 0; +} + +/* + * pru_can_get_global_status() Gets the globalstatus + * register value. This API will be called by the Application + * to get the global status register value + * + * return SUCCESS or FAILURE + */ +s16 pru_can_get_global_status(struct device *dev, + can_emu_app_hndl *pstremuapphndl) +{ + u32 u32offset; + int s16subrtnretval = -1; + + if (pstremuapphndl == NULL) { + return -1; + } + + if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) { + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER); + } else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) { + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER); + } else { + return -1; + } + + s16subrtnretval = pruss_readl(dev, u32offset, + (u32 *) &pstremuapphndl->u32globalstatus, 1); + if (s16subrtnretval == -1) { + return -1; + } + + return 0; +} + +/* + * pru_can_get_mailbox_status() Gets the mailbox status + * register value. This API will be called by the Application + * to get the mailbox status register value + * + * return SUCCESS or FAILURE + */ +s16 pru_can_get_mailbox_status(struct device *dev, + can_emu_app_hndl *pstremuapphndl) +{ + u32 u32offset; + s16 s16subrtnretval = -1; + + if (pstremuapphndl == NULL) { + return -1; + } + + if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_1) { + switch (pstremuapphndl->ecanmailboxnumber) { + case 0: + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER); + break; + case 1: + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER); + break; + case 2: + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER); + break; + case 3: + u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER); + break; + case 4: + u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER); + break; + case 5: + u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER); + break; + case 6: + u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER); + break; + case 7: + u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER); + break; + default: + return -1; + } + } + + else if (pstremuapphndl->u8prunumber == DA8XX_PRUCORE_0) { + switch (pstremuapphndl->ecanmailboxnumber) { + case 0: + u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER); + break; + case 1: + u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER); + break; + case 2: + u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER); + break; + case 3: + u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER); + break; + case 4: + u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER); + break; + case 5: + u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER); + break; + case 6: + u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER); + break; + case 7: + u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER); + break; + case 8: + u32offset = (PRU_CAN_RX_MAILBOX8_STATUS_REGISTER); + break; + default: + return -1; + } + } + + else { + return -1; + } + + s16subrtnretval = pruss_readl(dev, u32offset, + (u32 *) &pstremuapphndl->u32mailboxstatus, 1); + if (s16subrtnretval == -1) { + return -1; + } + + return 0; +} + +s16 pru_can_tx_mode_set(struct device *dev, bool btransfer_flag, + can_transfer_direction ecan_trx) +{ + u32 u32offset; + u32 u32value; + + if (ecan_trx == ecantransmit) { + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER); + pruss_readl(dev, u32offset, &u32value, 1); + if (btransfer_flag == true) { + u32value &= 0x1F; + u32value |= 0x80; + } else { + u32value &= 0x7F; + } + pruss_writel(dev, u32offset, &u32value, 1); + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER); + pruss_writel(dev, u32offset, &u32value, 1); + } else if (ecan_trx == ecanreceive) { + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER); + pruss_readl(dev, u32offset, &u32value, 1); + if (btransfer_flag == true) { + u32value &= 0x1F; + u32value |= 0x40; + } else { + u32value &= 0xBF; + } + pruss_writel(dev, u32offset, &u32value, 1); + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER); + pruss_writel(dev, u32offset, &u32value, 1); + } else + return -1; + + return 0; +} + +/* + * pru_can_config_mode_set() Sets the timing value + * for data transfer. This API will be called by the Application + * to set timing valus for data transfer + * + * return SUCCESS or FAILURE + */ +s16 pru_can_config_mode_set(struct device *dev, bool bconfigmodeflag) +{ + + u32 u32bitrateprescaler; + u32 u32canbittiming; + + pruss_readl(dev, (PRU_CAN_TX_CLOCK_BRP_REGISTER), + (u32 *) &u32bitrateprescaler, 1); + pruss_readl(dev, (PRU_CAN_TX_TIMING_REGISTER), + (u32 *) &u32canbittiming, 1); + + if (bconfigmodeflag == 1) { + pru_can_calc_timing(dev, u32canbittiming, u32bitrateprescaler); + } + + else { + pru_can_calc_timing(dev, 0, 0); + } + + return 0; +} + +/* + * pru_can_emu_init() Initializes the Can + * Emulation Parameters. This API will be called by the Application + * to Initialize the Can Emulation Parameters + * + * param u32pruclock PRU Clock value + * + * return SUCCESS or FAILURE + */ +s16 pru_can_emu_init(struct device *dev, u32 u32pruclock) +{ + u32 u32offset; + u32 u32value; + s16 s16subrtnretval = -1; + u8 u8loop; + + for (u8loop = 0; u8loop < (u8) ecanmaxinst; u8loop++) { + gstr_can_inst[u8loop].bcaninststate = (bool) 0; + gstr_can_inst[u8loop].ecantransferdirection = + (can_transfer_direction) 0; + gstr_can_inst[u8loop].u32apphandlerptr = 0; + } + + u32offset = (PRU_CAN_TX_GLOBAL_CONTROL_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_GLOBAL_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000040; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000040; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_INTERRUPT_MASK_REGISTER & 0xFFFF); + u32value = 0x00004000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_INTERRUPT_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = + pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000001; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_TIMING_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_CLOCK_BRP_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_TX_ERROR_COUNTER_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_POLARITY0 & 0xFFFF); + u32value = 0xFFFFFFFF; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = (PRUSS_INTC_POLARITY1 & 0xFFFF); + u32value = 0xFFFFFFFF; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = (PRUSS_INTC_TYPE0 & 0xFFFF); + u32value = 0x1C000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = (PRUSS_INTC_TYPE1 & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_HSTINTENIDXCLR & 0xFFFF); + u32value = 0x0; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_GLBLEN & 0xFFFF); + u32value = 0x1; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + /* tx intr map arm->pru */ + u32offset = (PRUSS_INTC_HSTINTENIDXSET & 0xFFFF); + u32value = 0x0; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_HOSTMAP0 & 0xFFFF); + u32value = 0x03020100; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_HOSTMAP1 & 0xFFFF); + u32value = 0x07060504; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_HOSTMAP2 & 0xFFFF); + u32value = 0x0000908; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_CHANMAP0 & 0xFFFF); + u32value = 0; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_CHANMAP8 & 0xFFFF); + u32value = 0x00020200; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF); + u32value = 32; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF); + u32value = 19; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF); + u32value = 19; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF); + u32value = 18; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF); + u32value = 18; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF); + u32value = 34; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF); + u32value = 34; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF); + u32value = 32; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRUSS_INTC_HOSTINTEN & 0xFFFF); + u32value = 0x5; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + +/* PRU0 - Rx Internal Registers Initializations */ + + u32offset = (PRU_CAN_RX_GLOBAL_CONTROL_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_GLOBAL_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000040; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_INTERRUPT_MASK_REGISTER & 0xFFFF); + u32value = 0x00004000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & 0xFFFF); + u32value = 0x0000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_ERROR_COUNTER_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_TIMING_REGISTER & 0xFFFF); + u32value = 0x0000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + u32offset = (PRU_CAN_RX_CLOCK_BRP_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + return 0; +} + + +/* + * pru_can_emu_open() Opens the can emu for + * application to use. This API will be called by the Application + * to Open the can emu for application to use. + * + * param pstremuapphndl Pointer to application handler + * structure + * + * return SUCCESS or FAILURE + */ +s16 pru_can_emu_open(struct device *dev, can_emu_app_hndl *pstremuapphndl) +{ + + if (pstremuapphndl == NULL) { + return -1; + } + + if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate == 1) { + return -1; + } + + gstr_can_inst[(u8) pstremuapphndl->ecaninstance]. + bcaninststate = (bool)1; + gstr_can_inst[(u8) pstremuapphndl-> + ecaninstance].ecantransferdirection = + (can_transfer_direction)(u8)pstremuapphndl->ecantransferdirection; + gstr_can_inst[(u8) pstremuapphndl->ecaninstance]. + u32apphandlerptr = (u32) pstremuapphndl; + + return 0; +} + + +/* + * brief pru_can_emu_close() Closes the can emu for other + * applications to use. This API will be called by the Application to Close + * the can emu for other applications to use + * + * param pstremuapphndl Pointer to application handler structure + * + * return SUCCESS or FAILURE + */ +s16 pru_can_emu_close(struct device *dev, can_emu_app_hndl *pstremuapphndl) +{ + + if (pstremuapphndl == NULL) { + return -1; + } + if (gstr_can_inst[pstremuapphndl->ecaninstance].bcaninststate == 0) { + return -1; + } + if ((u32) pstremuapphndl != gstr_can_inst[(u8) pstremuapphndl-> + ecaninstance].u32apphandlerptr){ + return -1; + } + gstr_can_inst[(u8) pstremuapphndl->ecaninstance].bcaninststate + = (bool) 0; + gstr_can_inst[(u8) pstremuapphndl-> + ecaninstance].ecantransferdirection = (can_transfer_direction) 0; + gstr_can_inst[(u8) pstremuapphndl->ecaninstance].u32apphandlerptr = 0; + + return 0; +} + +/* + * brief pru_can_emu_exit() Diables all the PRUs + * This API will be called by the Application to disable all PRUs + * param None + * return SUCCESS or FAILURE + */ +s16 pru_can_emu_exit(struct device *dev) +{ + s16 s16subrtnretval; + + s16subrtnretval = pruss_disable(dev, CAN_RX_PRU_0); + if (s16subrtnretval == -1) + return -1; + s16subrtnretval = pruss_disable(dev, CAN_TX_PRU_1); + if (s16subrtnretval == -1) + return -1; + + return 0; +} + +s16 pru_can_emu_sreset(struct device *dev) +{ + return 0; +} + +s16 pru_can_tx(struct device *dev, u8 u8mailboxnumber, u8 u8prunumber) +{ + u32 u32offset = 0; + u32 u32value = 0; + s16 s16subrtnretval = -1; + + if (DA8XX_PRUCORE_1 == u8prunumber) { + switch (u8mailboxnumber) { + case 0: + u32offset = (PRU_CAN_TX_MAILBOX0_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 1: + u32offset = (PRU_CAN_TX_MAILBOX1_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 2: + u32offset = (PRU_CAN_TX_MAILBOX2_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 3: + u32offset = (PRU_CAN_TX_MAILBOX3_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 4: + u32offset = (PRU_CAN_TX_MAILBOX4_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 5: + u32offset = (PRU_CAN_TX_MAILBOX5_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 6: + u32offset = (PRU_CAN_TX_MAILBOX6_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 7: + u32offset = (PRU_CAN_TX_MAILBOX7_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000080; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + default: + return -1; + } + } else { + + u32offset = (PRU_CAN_RX_INTERRUPT_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_readl(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + u32value = u32value & ~(1 << u8mailboxnumber); + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + + switch (u8mailboxnumber) { + case 0: + u32offset = (PRU_CAN_RX_MAILBOX0_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 1: + u32offset = (PRU_CAN_RX_MAILBOX1_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 2: + u32offset = (PRU_CAN_RX_MAILBOX2_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 3: + u32offset = (PRU_CAN_RX_MAILBOX3_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 4: + u32offset = (PRU_CAN_RX_MAILBOX4_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 5: + u32offset = (PRU_CAN_RX_MAILBOX5_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 6: + u32offset = (PRU_CAN_RX_MAILBOX6_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + case 7: + u32offset = (PRU_CAN_RX_MAILBOX7_STATUS_REGISTER & 0xFFFF); + u32value = 0x00000000; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + break; + default: + return -1; + } + } + return 0; +} + +s16 pru_can_start_abort_tx(struct device *dev, bool bcantransmitabortflag) +{ + u32 u32offset; + u32 u32value; + s16 s16subrtnretval; + u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF); + u32value = 32; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + + u32offset = (PRUSS_INTC_ENIDXSET & 0xFFFF); + u32value = 32; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + + u32offset = (PRUSS_INTC_STATIDXSET & 0xFFFF); + u32value = 32; + s16subrtnretval = pruss_writel(dev, u32offset, + (u32 *) &u32value, 1); + if (s16subrtnretval == -1) { + return -1; + } + return 0; +} + +s16 pru_can_mask_ints(struct device *dev, u32 int_mask) +{ + return 0; +} + +int pru_can_get_error_cnt(struct device *dev, u8 u8prunumber) +{ + return 0; +} + +int pru_can_get_intc_status(struct device *dev) +{ + u32 u32offset = 0; + u32 u32getvalue = 0; + u32 u32clrvalue = 0; + + u32offset = (PRUSS_INTC_STATCLRINT1 & 0xFFFF); + pruss_readl(dev, u32offset, (u32 *) &u32getvalue, 1); + + if (u32getvalue & 4) + u32clrvalue = 34; /* CLR Event 34 */ + + if (u32getvalue & 2) + u32clrvalue = 33; /* CLR Event 33 */ + + if (u32clrvalue) { + u32offset = (PRUSS_INTC_STATIDXCLR & 0xFFFF); + pruss_writel(dev, u32offset, &u32clrvalue, 1); + } else + return -1; + + return u32getvalue; +} diff --git a/drivers/net/can/da8xx_pruss/pruss_can_api.h b/drivers/net/can/da8xx_pruss/pruss_can_api.h new file mode 100644 index 0000000..7550456 --- /dev/null +++ b/drivers/net/can/da8xx_pruss/pruss_can_api.h @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Ganeshan N + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _PRU_CAN_API_H_ +#define _PRU_CAN_API_H_ + +#include +#include + + +#define CAN_BIT_TIMINGS (0x273) + +/* Timer Clock is sourced from DDR freq (PLL1 SYS CLK 2) */ +#define TIMER_CLK_FREQ 132000000 + +#define TIMER_SETUP_DELAY 14 +#define GPIO_SETUP_DELAY 150 + +#define CAN_RX_PRU_0 PRUSS_NUM0 +#define CAN_TX_PRU_1 PRUSS_NUM1 + +/* Number of Instruction in the Delay loop */ +#define DELAY_LOOP_LENGTH 2 + +#define PRU1_BASE_ADDR 0x2000 + +#define PRU_CAN_TX_GLOBAL_CONTROL_REGISTER (PRU1_BASE_ADDR) +#define PRU_CAN_TX_GLOBAL_STATUS_REGISTER (PRU1_BASE_ADDR + 0x04) +#define PRU_CAN_TX_INTERRUPT_MASK_REGISTER (PRU1_BASE_ADDR + 0x08) +#define PRU_CAN_TX_INTERRUPT_STATUS_REGISTER (PRU1_BASE_ADDR + 0x0C) +#define PRU_CAN_TX_MAILBOX0_STATUS_REGISTER (PRU1_BASE_ADDR + 0x10) +#define PRU_CAN_TX_MAILBOX1_STATUS_REGISTER (PRU1_BASE_ADDR + 0x14) +#define PRU_CAN_TX_MAILBOX2_STATUS_REGISTER (PRU1_BASE_ADDR + 0x18) +#define PRU_CAN_TX_MAILBOX3_STATUS_REGISTER (PRU1_BASE_ADDR + 0x1C) +#define PRU_CAN_TX_MAILBOX4_STATUS_REGISTER (PRU1_BASE_ADDR + 0x20) +#define PRU_CAN_TX_MAILBOX5_STATUS_REGISTER (PRU1_BASE_ADDR + 0x24) +#define PRU_CAN_TX_MAILBOX6_STATUS_REGISTER (PRU1_BASE_ADDR + 0x28) +#define PRU_CAN_TX_MAILBOX7_STATUS_REGISTER (PRU1_BASE_ADDR + 0x2C) +#define PRU_CAN_TX_ERROR_COUNTER_REGISTER (PRU1_BASE_ADDR + 0x30) +#define PRU_CAN_TX_TIMING_REGISTER (PRU1_BASE_ADDR + 0x34) +#define PRU_CAN_TX_CLOCK_BRP_REGISTER (PRU1_BASE_ADDR + 0x38) + +#define PRU_CAN_TX_MAILBOX0 (PRU1_BASE_ADDR + 0x40) +#define PRU_CAN_TX_MAILBOX1 (PRU1_BASE_ADDR + 0x50) +#define PRU_CAN_TX_MAILBOX2 (PRU1_BASE_ADDR + 0x60) +#define PRU_CAN_TX_MAILBOX3 (PRU1_BASE_ADDR + 0x70) +#define PRU_CAN_TX_MAILBOX4 (PRU1_BASE_ADDR + 0x80) +#define PRU_CAN_TX_MAILBOX5 (PRU1_BASE_ADDR + 0x90) +#define PRU_CAN_TX_MAILBOX6 (PRU1_BASE_ADDR + 0xA0) +#define PRU_CAN_TX_MAILBOX7 (PRU1_BASE_ADDR + 0xB0) + +#define PRU_CAN_TIMING_VAL_TX (PRU1_BASE_ADDR + 0xC0) +#define PRU_CAN_TIMING_VAL_TX_SJW (PRU1_BASE_ADDR + 0xC4) +#define PRU_CAN_TRANSMIT_FRAME (PRU1_BASE_ADDR + 0xE0) + +#define PRU0_BASE_ADDR 0 + +#define PRU_CAN_RX_GLOBAL_CONTROL_REGISTER (PRU0_BASE_ADDR) +#define PRU_CAN_RX_GLOBAL_STATUS_REGISTER (PRU0_BASE_ADDR + 0x04) +#define PRU_CAN_RX_INTERRUPT_MASK_REGISTER (PRU0_BASE_ADDR + 0x08) +#define PRU_CAN_RX_INTERRUPT_STATUS_REGISTER (PRU0_BASE_ADDR + 0x0C) +#define PRU_CAN_RX_MAILBOX0_STATUS_REGISTER (PRU0_BASE_ADDR + 0x10) +#define PRU_CAN_RX_MAILBOX1_STATUS_REGISTER (PRU0_BASE_ADDR + 0x14) +#define PRU_CAN_RX_MAILBOX2_STATUS_REGISTER (PRU0_BASE_ADDR + 0x18) +#define PRU_CAN_RX_MAILBOX3_STATUS_REGISTER (PRU0_BASE_ADDR + 0x1C) +#define PRU_CAN_RX_MAILBOX4_STATUS_REGISTER (PRU0_BASE_ADDR + 0x20) +#define PRU_CAN_RX_MAILBOX5_STATUS_REGISTER (PRU0_BASE_ADDR + 0x24) +#define PRU_CAN_RX_MAILBOX6_STATUS_REGISTER (PRU0_BASE_ADDR + 0x28) +#define PRU_CAN_RX_MAILBOX7_STATUS_REGISTER (PRU0_BASE_ADDR + 0x2C) +#define PRU_CAN_RX_MAILBOX8_STATUS_REGISTER (PRU0_BASE_ADDR + 0x30) +#define PRU_CAN_RX_ERROR_COUNTER_REGISTER (PRU0_BASE_ADDR + 0x34) +#define PRU_CAN_RX_TIMING_REGISTER (PRU0_BASE_ADDR + 0x38) +#define PRU_CAN_RX_CLOCK_BRP_REGISTER (PRU0_BASE_ADDR + 0x3C) + +#define PRU_CAN_RX_MAILBOX0 (PRU0_BASE_ADDR + 0x40) +#define PRU_CAN_RX_MAILBOX1 (PRU0_BASE_ADDR + 0x50) +#define PRU_CAN_RX_MAILBOX2 (PRU0_BASE_ADDR + 0x60) +#define PRU_CAN_RX_MAILBOX3 (PRU0_BASE_ADDR + 0x70) +#define PRU_CAN_RX_MAILBOX4 (PRU0_BASE_ADDR + 0x80) +#define PRU_CAN_RX_MAILBOX5 (PRU0_BASE_ADDR + 0x90) +#define PRU_CAN_RX_MAILBOX6 (PRU0_BASE_ADDR + 0xA0) +#define PRU_CAN_RX_MAILBOX7 (PRU0_BASE_ADDR + 0xB0) +#define PRU_CAN_RX_MAILBOX8 (PRU0_BASE_ADDR + 0xC0) + +#define PRU_CAN_TIMING_VAL_RX (PRU0_BASE_ADDR + 0xD0) +#define PRU_CAN_RECEIVE_FRAME (PRU0_BASE_ADDR + 0xD4) +#define PRU_CAN_ID_MAP (PRU0_BASE_ADDR + 0xF0) + +#define PRU_CAN_ERROR_ACTIVE 128 + +#define CAN_ACK_FAILED 0xE +#define CAN_ARBTR_FAIL 0xD +#define CAN_BIT_ERROR 0xC +#define CAN_TRANSMISSION_SUCCESS 0xA + +#define STD_DATA_FRAME 0x1 +#define EXTD_DATA_FRAME 0x2 +#define STD_REMOTE_FRAME 0x3 +#define EXTD_REMOTE_FRAME 0x4 + +#define PRU_CAN_MAX_SJW 8 +#define PRU_CAN_MAX_PHSEG1 25 +#define PRU_CAN_MAX_PHSEG2 25 + +#define DA8XX_PRUCANCORE_0_REGS 0x7000 +#define DA8XX_PRUCANCORE_1_REGS 0x7800 +#define PRU0_PROG_RAM_START_OFFSET 0x8000 +#define PRU1_PROG_RAM_START_OFFSET 0xC000 +#define PRU_CAN_INIT_MAX_TIMEOUT 0xFF + +typedef enum { + ecaninst0 = 0, + ecaninst1, + ecanmaxinst +} can_instance_enum; + +typedef enum { + ecanmailbox0 = 0, + ecanmailbox1, + ecanmailbox2, + ecanmailbox3, + ecanmailbox4, + ecanmailbox5, + ecanmailbox6, + ecanmailbox7 +} can_mailbox_number; + +typedef enum { + ecandirectioninit = 0, + ecantransmit, + ecanreceive +} can_transfer_direction; + +typedef struct { + u16 u16extendedidentifier; + u16 u16baseidentifier; + u8 u8data7; + u8 u8data6; + u8 u8data5; + u8 u8data4; + u8 u8data3; + u8 u8data2; + u8 u8data1; + u8 u8data0; + u16 u16datalength; + u16 u16crc; +} can_mail_box_structure; + +typedef struct { + can_transfer_direction ecantransferdirection; +} can_mailbox_config; + +typedef struct { + can_instance_enum ecaninstance; + can_transfer_direction ecantransferdirection; + can_mail_box_structure strcanmailbox; + can_mailbox_number ecanmailboxnumber; + u8 u8prunumber; + u32 u32globalstatus; + u32 u32interruptstatus; + u32 u32mailboxstatus; +} can_emu_app_hndl; + +typedef struct { + bool bcaninststate; + can_transfer_direction ecantransferdirection; + u32 u32apphandlerptr; +} can_emu_drv_inst; + +typedef struct { + u8 u8syncjumpwidth; + u8 u8phseg1; + u8 u8phseg2; +} can_bit_timing_consts; + +/* Field Definition Macros */ + +/* CONTROL */ + +/* + * pru_can_set_brp() Updates the BRP register of PRU. + */ +s16 pru_can_set_brp(struct device *dev, u16 u16prescaler); + +/* + * pru_can_set_bit_timing() Updates the timing register of PRU + */ +s16 pru_can_set_bit_timing(struct device *dev, + can_bit_timing_consts *pstrbittiming); + +/* + * pru_can_calc_timing() Updates the timing values of PRU + */ +s16 pru_can_calc_timing(struct device *dev, + u32 u32bittiming, u32 u32bitrateprescaler); + +/* + * pru_can_write_data_to_mailbox() Updates the transmit mailboxes of PRU1 + */ +s16 pru_can_write_data_to_mailbox(struct device *dev, + can_emu_app_hndl *pstremuapphndl); + +/* + * pru_can_get_data_from_mailbox() Receive data from receive mailboxes + */ +s16 pru_can_get_data_from_mailbox(struct device *dev, + can_emu_app_hndl *pstremuapphndl); + +/* + * pru_can_rx_id_map() Receive mailboxes ID Mapping of PRU0 + */ +s16 pru_can_rx_id_map(struct device *dev, + u32 u32nodeid, can_mailbox_number ecanmailboxno); + +/* + *pru_can_get_intr_status() Get interrupts status register value + */ +s16 pru_can_get_intr_status(struct device *dev, + can_emu_app_hndl *pstremuapphndl); + + +/* + * pru_can_get_global_status() Get the globalstatus register value + */ +s16 pru_can_get_global_status(struct device *dev, + can_emu_app_hndl *pstremuapphndl); + +/* + * pru_can_get_mailbox_status() Get mailbox status reg value + */ +s16 pru_can_get_mailbox_status(struct device *dev, + can_emu_app_hndl *pstremuapphndl); + +/* + * pru_can_configuration_mode_set() Sets timing val for data transfer + */ +s16 pru_can_config_mode_set(struct device *dev, + bool bconfig_modeflag); + +/* + * pru_can_emu_init() Initializes Can Emulation Parameters + */ +s16 pru_can_emu_init(struct device *dev, + u32 u32pruclock); + +/* + * pru_can_emu_open() Opens can emu for application to use + */ +s16 pru_can_emu_open(struct device *dev, + can_emu_app_hndl *pstremuapphndl); + +/* + * pru_can_emu_close() Closes can emu for applications to use + */ +s16 pru_can_emu_close(struct device *dev, + can_emu_app_hndl *pstremuapphndl); + +/* + * pru_can_emu_exit() Diables all the PRUs + */ +s16 pru_can_emu_exit(struct device *dev); + +s16 pru_can_tx_mode_set(struct device *dev, bool btransfer_flag, + can_transfer_direction ecan_trx); + +s16 pru_can_emu_sreset(struct device *dev); + +s16 pru_can_tx(struct device *dev, + u8 u8mailboxnumber, u8 u8prunumber); + +s16 pru_can_start_abort_tx(struct device *dev, + bool btxabort_flag); + +s16 pru_can_mask_ints(struct device *dev, u32 int_mask); + +s32 pru_can_get_error_cnt(struct device *dev, u8 u8prunumber); + +s32 pru_can_get_intc_status(struct device *dev); +#endif -- 1.7.2.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/