summaryrefslogtreecommitdiff
path: root/drivers/mfd/apalis-tk1-k20.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/apalis-tk1-k20.c')
-rw-r--r--drivers/mfd/apalis-tk1-k20.c96
1 files changed, 83 insertions, 13 deletions
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,