diff options
author | Dominik Sliwa <dominik.sliwa@toradex.com> | 2018-02-12 12:21:11 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2018-03-28 18:31:28 +0200 |
commit | e83f0920de7882d09816c57a1e78e253cc3dcd7c (patch) | |
tree | 61ce6651ef21c8d4469f363942254326b8a2d15c /drivers | |
parent | e2479101d95625c1c2fcb7c8f72fe515d9099cc1 (diff) |
can: mfd: apalis-tk1: v1.1 frequency adjustments and various fixes
Signed-off-by: Dominik Sliwa <dominik.sliwa@toradex.com>
Acked-by: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/apalis-tk1-k20-ezp.h | 2 | ||||
-rw-r--r-- | drivers/mfd/apalis-tk1-k20.c | 96 | ||||
-rw-r--r-- | drivers/net/can/apalis-tk1-k20-can.c | 104 |
3 files changed, 140 insertions, 62 deletions
diff --git a/drivers/mfd/apalis-tk1-k20-ezp.h b/drivers/mfd/apalis-tk1-k20-ezp.h index 922d55dcfe16..e89d6adbe471 100644 --- a/drivers/mfd/apalis-tk1-k20-ezp.h +++ b/drivers/mfd/apalis-tk1-k20-ezp.h @@ -37,7 +37,7 @@ #define APALIS_TK1_K20_EZP_STA_WEF BIT(6) #define APALIS_TK1_K20_EZP_STA_FS BIT(7) -#define APALIS_TK1_K20_EZP_MAX_SPEED 3500000 +#define APALIS_TK1_K20_EZP_MAX_SPEED 4080000 #define APALIS_TK1_K20_EZP_MAX_DATA 32 #define APALIS_TK1_K20_EZP_WRITE_SIZE 32 diff --git a/drivers/mfd/apalis-tk1-k20.c b/drivers/mfd/apalis-tk1-k20.c index 1ab5542af0d1..e794bda6fde7 100644 --- a/drivers/mfd/apalis-tk1-k20.c +++ b/drivers/mfd/apalis-tk1-k20.c @@ -20,6 +20,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_gpio.h> +#include <linux/of_irq.h> #include <linux/err.h> #include <linux/firmware.h> #include <linux/spi/spi.h> @@ -67,7 +68,8 @@ static int apalis_tk1_k20_spi_read(void *context, const void *reg, size_t reg_size, void *val, size_t val_size) { unsigned char w[APALIS_TK1_K20_MAX_BULK] = {APALIS_TK1_K20_READ_INST, - *((unsigned char *) reg), val_size, 0x00, 0x00}; + *((unsigned char *) reg), val_size, 0x00, 0x00, 0x00, + 0x00}; unsigned char r[APALIS_TK1_K20_MAX_BULK]; unsigned char *p = val; struct device *dev = context; @@ -75,7 +77,7 @@ static int apalis_tk1_k20_spi_read(void *context, const void *reg, struct spi_transfer t = { .tx_buf = w, .rx_buf = r, - .len = 6, + .len = 8, .cs_change = 0, .delay_usecs = 0, }; @@ -91,11 +93,35 @@ static int apalis_tk1_k20_spi_read(void *context, const void *reg, spi_message_init(&m); spi_message_add_tail(&t, &m); ret = spi_sync(spi, &m); - *p = ((unsigned char *)t.rx_buf)[5]; + + for (int i = 3; i < 7; i++ ) + { + if (((unsigned char *)t.rx_buf)[i] == 0x55) { + *p = ((unsigned char *)t.rx_buf)[i + 1]; + return ret; + } + } + + for (int j = 0; j < APALIS_TK1_MAX_RETRY_CNT; j++) { + udelay(250 * j * j); + t.tx_buf = w; + t.rx_buf = r; + spi_message_init(&m); + spi_message_add_tail(&t, &m); + ret = spi_sync(spi, &m); + for (int i = 3; i < 7; i++ ) + { + if (((unsigned char *)t.rx_buf)[i] == 0x55) { + *p = ((unsigned char *)t.rx_buf)[i + 1]; + return ret; + } + } + } + ret = -EIO; #ifdef CONFIG_V12_K20_HSMODE } else if ((val_size > 1) && (val_size < APALIS_TK1_K20_MAX_BULK)) { - t.len = 3; + t.len = 5; w[0] = APALIS_TK1_K20_BULK_READ_INST; spi_message_init(&m); spi_message_add_tail(&t, &m); @@ -135,8 +161,9 @@ static int apalis_tk1_k20_spi_write(void *context, const void *data, #ifdef CONFIG_V12_K20_HSMODE } else if ((count > 2) && (count < APALIS_TK1_K20_MAX_BULK)) { out_data[0] = APALIS_TK1_K20_BULK_WRITE_INST; - out_data[1] = count - 1; - memcpy(&out_data[2], data, count); + out_data[1] = ((uint8_t *)data)[0]; + out_data[2] = count - 1; + memcpy(&out_data[3], &((uint8_t *)data)[1], count - 1); ret = spi_write(spi, out_data, count + 2); #endif } else { @@ -239,7 +266,14 @@ EXPORT_SYMBOL(apalis_tk1_k20_reg_rmw); int apalis_tk1_k20_irq_mask(struct apalis_tk1_k20_regmap *apalis_tk1_k20, int irq) { - int virq = regmap_irq_get_virq(apalis_tk1_k20->irq_data, irq); + int virq = -1; + if (irq != APALIS_TK1_K20_CAN1_IRQ && irq != APALIS_TK1_K20_CAN0_IRQ) { + virq = regmap_irq_get_virq(apalis_tk1_k20->irq_data, irq); + + } else { + virq = (irq == APALIS_TK1_K20_CAN0_IRQ) ? + apalis_tk1_k20->can0_irq:apalis_tk1_k20->can1_irq; + } disable_irq_nosync(virq); @@ -250,7 +284,14 @@ EXPORT_SYMBOL(apalis_tk1_k20_irq_mask); int apalis_tk1_k20_irq_unmask(struct apalis_tk1_k20_regmap *apalis_tk1_k20, int irq) { - int virq = regmap_irq_get_virq(apalis_tk1_k20->irq_data, irq); + int virq = -1; + if (irq != APALIS_TK1_K20_CAN1_IRQ && irq != APALIS_TK1_K20_CAN0_IRQ) { + virq = regmap_irq_get_virq(apalis_tk1_k20->irq_data, irq); + + } else { + virq = (irq == APALIS_TK1_K20_CAN0_IRQ) ? + apalis_tk1_k20->can0_irq:apalis_tk1_k20->can1_irq; + } enable_irq(virq); @@ -296,17 +337,33 @@ EXPORT_SYMBOL(apalis_tk1_k20_irq_status); int apalis_tk1_k20_irq_request(struct apalis_tk1_k20_regmap *apalis_tk1_k20, int irq, irq_handler_t handler, const char *name, void *dev) { - int virq = regmap_irq_get_virq(apalis_tk1_k20->irq_data, irq); - - return devm_request_threaded_irq(apalis_tk1_k20->dev, virq, NULL, - handler, IRQF_ONESHOT, name, dev); + int virq = -1; + int irq_flags = IRQF_ONESHOT; + if (irq != APALIS_TK1_K20_CAN1_IRQ && irq != APALIS_TK1_K20_CAN0_IRQ) { + virq = regmap_irq_get_virq(apalis_tk1_k20->irq_data, irq); + irq_flags = IRQF_ONESHOT; + } else { + virq = (irq == APALIS_TK1_K20_CAN0_IRQ) ? + apalis_tk1_k20->can0_irq:apalis_tk1_k20->can1_irq; + irq_flags = IRQF_ONESHOT | IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING; + } + return devm_request_threaded_irq(apalis_tk1_k20->dev, virq, + NULL, handler, irq_flags, name, dev); } EXPORT_SYMBOL(apalis_tk1_k20_irq_request); int apalis_tk1_k20_irq_free(struct apalis_tk1_k20_regmap *apalis_tk1_k20, int irq, void *dev) { - int virq = regmap_irq_get_virq(apalis_tk1_k20->irq_data, irq); + int virq = -1; + if (irq != APALIS_TK1_K20_CAN1_IRQ && irq != APALIS_TK1_K20_CAN0_IRQ) { + virq = regmap_irq_get_virq(apalis_tk1_k20->irq_data, irq); + + } else { + virq = (irq == APALIS_TK1_K20_CAN0_IRQ) ? + apalis_tk1_k20->can0_irq:apalis_tk1_k20->can1_irq; + } devm_free_irq(apalis_tk1_k20->dev, virq, dev); @@ -844,6 +901,19 @@ int apalis_tk1_k20_dev_init(struct device *dev) if (apalis_tk1_k20_probe_flags_dt(apalis_tk1_k20) < 0 && pdata) apalis_tk1_k20->flags = pdata->flags; + if (apalis_tk1_k20->flags & APALIS_TK1_K20_USES_CAN) { + apalis_tk1_k20->can0_irq = irq_of_parse_and_map( + apalis_tk1_k20->dev->of_node, 1); + apalis_tk1_k20->can1_irq = irq_of_parse_and_map( + apalis_tk1_k20->dev->of_node, 2); + if (apalis_tk1_k20->can0_irq == 0 || + apalis_tk1_k20->can1_irq == 0) { + apalis_tk1_k20->flags &= ~APALIS_TK1_K20_USES_CAN; + dev_err(apalis_tk1_k20->dev, + "Missing CAN interrupts.\n"); + } + } + if (pdata) { if (apalis_tk1_k20->flags & APALIS_TK1_K20_USES_TSC) apalis_tk1_k20_add_subdevice_pdata(apalis_tk1_k20, diff --git a/drivers/net/can/apalis-tk1-k20-can.c b/drivers/net/can/apalis-tk1-k20-can.c index c32a70181ac1..53f64189a7fb 100644 --- a/drivers/net/can/apalis-tk1-k20-can.c +++ b/drivers/net/can/apalis-tk1-k20-can.c @@ -34,22 +34,20 @@ #define CAN_FRAME_MAX_LEN 8 #define CAN_HEADER_MAX_LEN 5 #define CAN_TRANSFER_BUF_LEN (CAN_HEADER_MAX_LEN + CAN_FRAME_MAX_LEN) -#define CAN_FRAME_MAX_BITS 128 -#define CAN_MAX_CONTINUOUS_READ 8 -#define MB_DLC_OFF 0 -#define MB_EID_OFF 1 +#define MB_DLC_OFF 4 +#define MB_EID_OFF 0 #define MB_RTR_SHIFT 4 #define MB_IDE_SHIFT 5 #define MB_DLC_MASK 0xF #define MB_EID_LEN 4 #define CANCTRL_MODMASK 0x03 -#define CANCTRL_INTMASK 0x38 #define CANCTRL_INTEN BIT(2) #define CANINTF_RX BIT(3) #define CANINTF_TX BIT(4) #define CANINTF_ERR BIT(5) +#define CANCTRL_INTMASK (CANINTF_RX | CANINTF_TX | CANINTF_ERR) #define EFLG_EWARN 0x01 #define EFLG_RXWAR 0x02 @@ -140,42 +138,50 @@ static void apalis_tk1_k20_can_hw_tx(struct net_device *net, + CAN_HEADER_MAX_LEN, tx_buf_idx); } -static void apalis_tk1_k20_can_hw_rx_frame(struct net_device *net, u8 *buf, - int buf_idx) +static void apalis_tk1_k20_can_hw_rx(struct net_device *net, int buf_idx) { struct apalis_tk1_k20_priv *priv = netdev_priv(net); + struct sk_buff *skb; + struct can_frame *frame; + u8 buf[CAN_TRANSFER_BUF_LEN * APALIS_TK1_MAX_CAN_DMA_XREF]; + u32 frame_available = 0; apalis_tk1_k20_lock(priv->apalis_tk1_k20); - + apalis_tk1_k20_reg_read(priv->apalis_tk1_k20, + APALIS_TK1_K20_CAN_IN_BUF_CNT + + APALIS_TK1_K20_CAN_DEV_OFFSET( + priv->pdata->id), &frame_available); + frame_available = min(frame_available, APALIS_TK1_MAX_CAN_DMA_XREF); apalis_tk1_k20_reg_read_bulk(priv->apalis_tk1_k20, APALIS_TK1_K20_CAN_IN_BUF + APALIS_TK1_K20_CAN_DEV_OFFSET( priv->pdata->id), buf, - CAN_TRANSFER_BUF_LEN); + CAN_TRANSFER_BUF_LEN * frame_available); apalis_tk1_k20_unlock(priv->apalis_tk1_k20); -} - -static void apalis_tk1_k20_can_hw_rx(struct net_device *net, int buf_idx) -{ - struct apalis_tk1_k20_priv *priv = netdev_priv(net); - struct sk_buff *skb; - struct can_frame *frame; - skb = alloc_can_skb(priv->net, &frame); - if (!skb) { - dev_err(&net->dev, "cannot allocate RX skb\n"); - priv->net->stats.rx_dropped++; - return; - } + for (int i = 0; i < frame_available; i++) { + skb = alloc_can_skb(priv->net, &frame); + if (!skb) { + dev_err(&net->dev, "cannot allocate RX skb\n"); + priv->net->stats.rx_dropped++; + return; + } + memcpy(&frame->can_id, &buf[i * CAN_TRANSFER_BUF_LEN] + + MB_EID_OFF, MB_EID_LEN); + /* Data length */ + frame->can_dlc = get_can_dlc(buf[i * CAN_TRANSFER_BUF_LEN + + MB_DLC_OFF]); + memcpy(frame->data, &buf[i * CAN_TRANSFER_BUF_LEN] + + CAN_HEADER_MAX_LEN, frame->can_dlc); - apalis_tk1_k20_can_hw_rx_frame(net, (unsigned char *)frame, buf_idx); + priv->net->stats.rx_packets++; + priv->net->stats.rx_bytes += frame->can_dlc; - priv->net->stats.rx_packets++; - priv->net->stats.rx_bytes += frame->can_dlc; + can_led_event(priv->net, CAN_LED_EVENT_RX); - can_led_event(priv->net, CAN_LED_EVENT_RX); + netif_rx_ni(skb); + } - netif_rx_ni(skb); } @@ -503,10 +509,9 @@ static irqreturn_t apalis_tk1_k20_can_ist(int irq, void *dev_id) { struct apalis_tk1_k20_priv *priv = dev_id; struct net_device *net = priv->net; - int max_continuous_read = CAN_MAX_CONTINUOUS_READ; mutex_lock(&priv->apalis_tk1_k20_can_lock); - while (!priv->force_quit && max_continuous_read) { + while (!priv->force_quit) { enum can_state new_state; int ret; u32 intf, eflag; @@ -525,39 +530,37 @@ static irqreturn_t apalis_tk1_k20_can_ist(int irq, void *dev_id) break; } - max_continuous_read--; - intf &= CANCTRL_INTMASK; /* receive */ if (intf & CANINTF_RX) apalis_tk1_k20_can_hw_rx(net, 0); - /* any error or TX interrupt we need to clear? */ - if (intf & (CANINTF_ERR | CANINTF_TX)) - clear_intf |= intf & (CANINTF_ERR | CANINTF_TX); + /* any error interrupt we need to clear? */ + if (intf & CANINTF_ERR) + clear_intf |= intf & CANINTF_ERR; apalis_tk1_k20_lock(priv->apalis_tk1_k20); if (clear_intf) - ret = apalis_tk1_k20_reg_rmw(priv->apalis_tk1_k20, - APALIS_TK1_K20_CANREG + - APALIS_TK1_K20_CAN_DEV_OFFSET( - priv->pdata->id), - CANCTRL_INTMASK, 0x00); + ret = apalis_tk1_k20_reg_write(priv->apalis_tk1_k20, + APALIS_TK1_K20_CANREG_CLR + + APALIS_TK1_K20_CAN_DEV_OFFSET( + priv->pdata->id),clear_intf); if (ret) { apalis_tk1_k20_unlock(priv->apalis_tk1_k20); dev_err(&net->dev, "Communication error\n"); break; } - ret = apalis_tk1_k20_reg_read(priv->apalis_tk1_k20, - APALIS_TK1_K20_CANERR + - APALIS_TK1_K20_CAN_DEV_OFFSET( - priv->pdata->id), &eflag); - apalis_tk1_k20_unlock(priv->apalis_tk1_k20); - if (ret) { - dev_err(&net->dev, "Communication error\n"); - break; - } + /* Update can state */ if (intf & CANINTF_ERR) { + ret = apalis_tk1_k20_reg_read(priv->apalis_tk1_k20, + APALIS_TK1_K20_CANERR + + APALIS_TK1_K20_CAN_DEV_OFFSET( + priv->pdata->id), &eflag); + apalis_tk1_k20_unlock(priv->apalis_tk1_k20); + if (ret) { + dev_err(&net->dev, "Communication error\n"); + break; + } if (eflag & EFLG_TXBO) { new_state = CAN_STATE_BUS_OFF; can_id |= CAN_ERR_BUSOFF; @@ -581,6 +584,9 @@ static irqreturn_t apalis_tk1_k20_can_ist(int irq, void *dev_id) new_state = CAN_STATE_ERROR_ACTIVE; } } + else { + apalis_tk1_k20_unlock(priv->apalis_tk1_k20); + } /* Update can state statistics */ switch (priv->can.state) { @@ -630,6 +636,8 @@ static irqreturn_t apalis_tk1_k20_can_ist(int irq, void *dev_id) priv->tx_len = 0; } netif_wake_queue(net); + if (!(intf & (CANINTF_RX | CANINTF_ERR))) + break; } } mutex_unlock(&priv->apalis_tk1_k20_can_lock); |