[MinnowBoard] Multiple SPI CS lines on MinnowBoard Max
Damien Dusha
d.dusha at gmail.com
Thu Jun 25 03:05:15 UTC 2015
Hi John,
On Thu, Jun 25, 2015 at 9:41 AM, John Hawley <john.hawley at intel.com> wrote:
> On 06/24/2015 04:17 PM, Damien Dusha wrote:
>> Dear All,
>>
>> I have been looking at having multiple chip selects on the SPI
>> peripheral of the MinnowBoard Max (Bay Trail). The hardware only
>> natively supports one CS line and therefore using GPIO(s) as chip
>> select is necessary. This topic has previously been discussed in
>> generalities on this mailing list [1].
>
> So this is fantastic news, and I'm glad that it's working. Next steps,
> as you've surmised, is likely to have a chat with the maintainers, who
> look to be:
>
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/MAINTAINERS#n8012
Agreed.
> Do you have your
> changed version of the code, might be worth looking at what you did to
> get it to work to try and figure out something to discuss with the
> maintainers.
>
Attached are the patches to make it work, complete and working against
vanilla kernel v4.0.0, running Fedora 22. The two SPI devices are
standard MCP2515 CAN controllers for which there is already a mainline
driver. The board file includes details on how it was wired up to a
standard development kit.
-- Damien
>From 5bd32df0ba5db3e4eb73bfeb9a72844135031eb4 Mon Sep 17 00:00:00 2001
From: Damien Dusha <d.dusha at gmail.com>
Date: Thu, 25 Jun 2015 09:38:04 +1000
Subject: [PATCH 1/2] Allow more than one CS for the Bay Trail SPI driver
---
drivers/spi/spi-pxa2xx-pci.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index fa7399e..0907102 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -64,7 +64,7 @@ static struct pxa_spi_info spi_info_configs[] = {
[PORT_BYT] = {
.type = LPSS_SSP,
.port_id = 0,
- .num_chipselect = 1,
+ .num_chipselect = 2, /* HACK: Allow more than one CS for
Bay Trail */
.max_clk_rate = 50000000,
.tx_param = &byt_tx_param,
.rx_param = &byt_rx_param,
--
2.4.0
>From 243687bf3db0258a779781f8ad31502cb6637a42 Mon Sep 17 00:00:00 2001
From: Damien Dusha <d.dusha at gmail.com>
Date: Thu, 25 Jun 2015 11:00:17 +1000
Subject: [PATCH 2/2] Add minnowboard max dual can lure
---
drivers/platform/x86/Kconfig | 10 ++
drivers/platform/x86/Makefile | 1 +
drivers/platform/x86/minnowmax-dual-can.c | 250 ++++++++++++++++++++++++++++++
3 files changed, 261 insertions(+)
create mode 100644 drivers/platform/x86/minnowmax-dual-can.c
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 9752761..f2a8932 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -604,6 +604,16 @@ config TOPSTAR_LAPTOP
If you have a Topstar laptop, say Y or M here.
+config MINNOWMAX_DUAL_CAN
+ tristate "Dual CAN Lure for MinnowBoard Max"
+ depends on SPI_MASTER && GPIOLIB
+ ---help---
+ This driver adds support for Dual SPI CAN chips (MCP2515)
+ connected to the low-speed expansion header of the MinnowBoard
+ Max.
+
+ Only say yes if you have a Dual CAN Lure for MinnowBoard Max
+
config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on ACPI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index f82232b..d731460 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ACPI_WMI) += wmi.o
obj-$(CONFIG_MSI_WMI) += msi-wmi.o
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
+obj-$(CONFIG_MINNOWMAX_DUAL_CAN) += minnowmax-dual-can.o
# toshiba_acpi must link after wmi to ensure that wmi devices are found
# before toshiba_acpi initializes
diff --git a/drivers/platform/x86/minnowmax-dual-can.c
b/drivers/platform/x86/minnowmax-dual-can.c
new file mode 100644
index 0000000..dace415
--- /dev/null
+++ b/drivers/platform/x86/minnowmax-dual-can.c
@@ -0,0 +1,250 @@
+/*
+ * Dual SPI CAN Lure for MinnowBoard Max
+ * Copyright (C) 2015, Damien Dusha <d.dusha at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * Author: Damien Dusha <d.dusha at gmail.com>
+ */
+
+/*
+ * This is a proof-of-concept for a MinnowMax Lure using multiple GPIOs as
+ * chip selects for the SPI peripheral on the Bay Trail. For this driver to
+ * work, the following HW is required:
+ *
+ * 2x Microchip MCP2515 SPI CAN, wired as follows to the low-speed header:
+ * - CAN0: nCS connected to GPIO_I2S_DI (Pin 20)
+ * nIRQ connected to GPIO_IBL_8254 (Pin 26)
+ * - CAN1: nCS connected to GPIO_S5_0 (Pin 21)
+ * nIRQ connected to GPIO_S5_1 (Pin 23)
+ *
+ * Common to both are MOSI, MISO, SCK. The hardware CS is unconnected.
+ *
+ * For testing purposes, it is easy enough to wire up two "MPC2515 PICTail
+ * Plus" evaluation kits (Microchip P/N: mcp2515dm-ptpls) available from
+ * DigiKey and Mouser (or your favourite distributor). It is safe to wire
+ * the EVK to 3.3V, but don't expect anything out the actual bus unless the
+ * CAN transceiver is replaced with a 3.3V compatible tranceiver (e.g.
+ * pin-compatible TI SN65HVD233). Do not wire up 5V unless there are level
+ * translators on the I/O lines to the MinnowMax.
+ *
+ * To use this driver, the spi-pxa2xx-pci.c driver must be patched. Change
+ * the num_chipselect for BYT to 2. Insertion of this module will fail if
+ * this change is not made.
+ */
+
+
+#define pr_fmt(fmt) "minnowmax-dual-can: " fmt
+
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/pxa2xx_spi.h>
+#include <linux/can/platform/mcp251x.h>
+
+#define MPC2515_CAN0_SPI_BUS 0
+#define MPC2515_CAN1_SPI_BUS 0
+
+#define MCP2515_CAN0_SPI_CS 0
+#define MCP2515_CAN1_SPI_CS 1
+
+#define MCP2515_CAN0_MAX_CLK_HZ (2 * 1000 * 1000)
+#define MCP2515_CAN1_MAX_CLK_HZ (2 * 1000 * 1000)
+
+#define GPIO_CAN0_nIRQ 464
+#define GPIO_CAN1_nIRQ 339
+
+#define GPIO_CAN0_nCS 474
+#define GPIO_CAN1_nCS 338
+
+#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
+
+
+static struct pxa2xx_spi_chip mcp2515_can0_spi_chip_info = {
+ .tx_threshold = 8,
+ .rx_threshold = 128,
+ .dma_burst_size = 8,
+ .timeout = 235,
+ .gpio_cs = GPIO_CAN0_nCS
+};
+
+static struct pxa2xx_spi_chip mcp2515_can1_spi_chip_info = {
+ .tx_threshold = 8,
+ .rx_threshold = 128,
+ .dma_burst_size = 8,
+ .timeout = 235,
+ .gpio_cs = GPIO_CAN1_nCS
+};
+
+
+static struct mcp251x_platform_data mcp2515_can0_info = {
+ .oscillator_frequency = (20 * 1000 * 1000),
+};
+
+static struct mcp251x_platform_data mcp2515_can1_info = {
+ .oscillator_frequency = (20 * 1000 * 1000),
+};
+
+static struct spi_board_info mcp2515_spi_board_info[] = {
+ {
+ .modalias = "mcp2515",
+ .mode = SPI_MODE_0,
+ .max_speed_hz = MCP2515_CAN0_MAX_CLK_HZ,
+ .bus_num = MPC2515_CAN0_SPI_BUS,
+ .chip_select = MCP2515_CAN0_SPI_CS,
+ .platform_data = &mcp2515_can0_info,
+ .controller_data = &mcp2515_can0_spi_chip_info,
+ .irq = 0
+ },
+ {
+ .modalias = "mcp2515",
+ .mode = SPI_MODE_0,
+ .max_speed_hz = MCP2515_CAN1_MAX_CLK_HZ,
+ .bus_num = MPC2515_CAN1_SPI_BUS,
+ .chip_select = MCP2515_CAN1_SPI_CS,
+ .platform_data = &mcp2515_can1_info,
+ .controller_data = &mcp2515_can1_spi_chip_info,
+ .irq = 0
+ },
+};
+
+static struct spi_device *mcp2515_can0_dev = NULL;
+static struct spi_device *mcp2515_can1_dev = NULL;
+
+static int __init register_gpios(void)
+{
+ int err_gpio;
+
+ err_gpio = gpio_request_one(GPIO_CAN0_nIRQ, GPIOF_DIR_IN, "CAN0 nIRQ");
+ pr_debug("err_gpio (GPIO_CAN0_nIRQ) = %d\n", err_gpio);
+ if (err_gpio)
+ goto fail_gpio_can0_irq;
+
+ err_gpio = gpio_request_one(GPIO_CAN1_nIRQ, GPIOF_DIR_IN, "CAN1 nIRQ");
+ pr_debug("err_gpio (GPIO_CAN1_nIRQ) = %d\n", err_gpio);
+ if (err_gpio)
+ goto fail_gpio_can1_irq;
+
+ return err_gpio;
+
+fail_gpio_can1_irq:
+
+ gpio_free(GPIO_CAN0_nIRQ);
+
+fail_gpio_can0_irq:
+
+ return err_gpio;
+}
+
+static void unregister_gpios(void)
+{
+ gpio_free(GPIO_CAN0_nIRQ);
+ gpio_free(GPIO_CAN1_nIRQ);
+}
+
+static int setup_irqs(void)
+{
+ int irq_num_can0;
+ int irq_num_can1;
+
+ int irq_err;
+
+ irq_num_can0 = gpio_to_irq(GPIO_CAN0_nIRQ);
+ pr_debug("irq_num_can0 = %d\n", irq_num_can0);
+
+ irq_num_can1 = gpio_to_irq(GPIO_CAN1_nIRQ);
+ pr_debug("irq_num_can1 = %d\n", irq_num_can1);
+
+ irq_err = irq_set_irq_type(irq_num_can0, IRQ_TYPE_EDGE_FALLING);
+ pr_debug("irq_err_can0 = %d\n", irq_err);
+ if (irq_err)
+ goto fail_set_irq_type;
+
+ irq_err = irq_set_irq_type(irq_num_can1, IRQ_TYPE_EDGE_FALLING);
+ pr_debug("irq_err_can1 = %d\n", irq_err);
+ if (irq_err)
+ goto fail_set_irq_type;
+
+ /* Assign the IRQ to the SPI device */
+ mcp2515_spi_board_info[0].irq = irq_num_can0;
+ mcp2515_spi_board_info[1].irq = irq_num_can1;
+
+fail_set_irq_type:
+
+ return irq_err;
+}
+
+
+static int __init minnowmax_dual_can_module_init(void)
+{
+ struct spi_master *master;
+ int err;
+
+ err = -ENODEV;
+
+ if (register_gpios())
+ goto fail_request_gpios;
+
+ if (setup_irqs())
+ goto fail_set_irq_type;
+
+ master = spi_busnum_to_master(MPC2515_CAN0_SPI_BUS);
+ if (!master)
+ goto fail_spi_busnum;
+
+ mcp2515_can0_dev = spi_new_device(master, &mcp2515_spi_board_info[0]);
+ if (!mcp2515_can0_dev)
+ goto fail_register_can0;
+
+ mcp2515_can1_dev = spi_new_device(master, &mcp2515_spi_board_info[1]);
+ if (!mcp2515_can1_dev)
+ goto fail_register_can1;
+
+ pr_info("minnowmax-dual-can: Registered MinnowMax Dual CAN Lure");
+
+ err = 0;
+ return err;
+
+fail_register_can1:
+
+ if (mcp2515_can0_dev)
+ spi_unregister_device(mcp2515_can0_dev);
+
+fail_register_can0:
+fail_spi_busnum:
+fail_set_irq_type:
+
+ unregister_gpios();
+
+fail_request_gpios:
+
+ pr_err("minnowmax-dual-can: Failed to register MinnowMax Dual CAN Lure\n");
+ return err;
+}
+
+static void __exit minnowmax_dual_can_module_exit(void)
+{
+ if (mcp2515_can0_dev)
+ spi_unregister_device(mcp2515_can0_dev);
+
+ if (mcp2515_can1_dev)
+ spi_unregister_device(mcp2515_can1_dev);
+
+ unregister_gpios();
+}
+
+module_init(minnowmax_dual_can_module_init);
+module_exit(minnowmax_dual_can_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Damien Dusha <d.dusha at gmail.com>");
+MODULE_DESCRIPTION("MinnowBoard Max Dual CAN Lure");
--
2.4.0
More information about the elinux-MinnowBoard
mailing list