diff options
author | Jan Glauber <jglauber@cavium.com> | 2016-08-19 10:03:20 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-08-19 11:24:39 -0400 |
commit | 7347a6c7af8d9b5edf587678e80c7e5bc24ec2d5 (patch) | |
tree | aa1ce6b9ef511aed1e1dbb55d1aab8941f77977d /drivers/spi | |
parent | 29b4817d4018df78086157ea3a55c1d9424a7cfc (diff) |
spi: octeon: Add ThunderX driver
Add ThunderX SPI driver using the shared part from the Octeon
driver. The main difference of the ThunderX driver is that it
is a PCI device so probing is different. The system clock settings
can be specified in device tree.
Signed-off-by: Jan Glauber <jglauber@cavium.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/Kconfig | 7 | ||||
-rw-r--r-- | drivers/spi/Makefile | 2 | ||||
-rw-r--r-- | drivers/spi/spi-cavium-thunderx.c | 118 | ||||
-rw-r--r-- | drivers/spi/spi-cavium.h | 3 |
4 files changed, 130 insertions, 0 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index d6fb8d4b7786..8108971af601 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
@@ -631,6 +631,13 @@ config SPI_TEGRA20_SLINK | |||
631 | help | 631 | help |
632 | SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. | 632 | SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. |
633 | 633 | ||
634 | config SPI_THUNDERX | ||
635 | tristate "Cavium ThunderX SPI controller" | ||
636 | depends on PCI && 64BIT && (ARM64 || COMPILE_TEST) | ||
637 | help | ||
638 | SPI host driver for the hardware found on Cavium ThunderX | ||
639 | SOCs. | ||
640 | |||
634 | config SPI_TOPCLIFF_PCH | 641 | config SPI_TOPCLIFF_PCH |
635 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI" | 642 | tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI" |
636 | depends on PCI && (X86_32 || MIPS || COMPILE_TEST) | 643 | depends on PCI && (X86_32 || MIPS || COMPILE_TEST) |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 185367ef6576..133364b069e6 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
@@ -91,6 +91,8 @@ obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o | |||
91 | obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o | 91 | obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o |
92 | obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o | 92 | obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o |
93 | obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o | 93 | obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o |
94 | spi-thunderx-objs := spi-cavium.o spi-cavium-thunderx.o | ||
95 | obj-$(CONFIG_SPI_THUNDERX) += spi-thunderx.o | ||
94 | obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o | 96 | obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o |
95 | obj-$(CONFIG_SPI_TXX9) += spi-txx9.o | 97 | obj-$(CONFIG_SPI_TXX9) += spi-txx9.o |
96 | obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o | 98 | obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o |
diff --git a/drivers/spi/spi-cavium-thunderx.c b/drivers/spi/spi-cavium-thunderx.c new file mode 100644 index 000000000000..eff2a130ef0c --- /dev/null +++ b/drivers/spi/spi-cavium-thunderx.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * Cavium ThunderX SPI driver. | ||
3 | * | ||
4 | * Copyright (C) 2016 Cavium Inc. | ||
5 | * Authors: Jan Glauber <jglauber@cavium.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/pci.h> | ||
10 | #include <linux/spi/spi.h> | ||
11 | |||
12 | #include "spi-cavium.h" | ||
13 | |||
14 | #define DRV_NAME "spi-thunderx" | ||
15 | |||
16 | #define SYS_FREQ_DEFAULT 700000000 /* 700 Mhz */ | ||
17 | |||
18 | static int thunderx_spi_probe(struct pci_dev *pdev, | ||
19 | const struct pci_device_id *ent) | ||
20 | { | ||
21 | struct device *dev = &pdev->dev; | ||
22 | struct spi_master *master; | ||
23 | struct octeon_spi *p; | ||
24 | int ret; | ||
25 | |||
26 | master = spi_alloc_master(dev, sizeof(struct octeon_spi)); | ||
27 | if (!master) | ||
28 | return -ENOMEM; | ||
29 | |||
30 | p = spi_master_get_devdata(master); | ||
31 | |||
32 | ret = pcim_enable_device(pdev); | ||
33 | if (ret) | ||
34 | goto error; | ||
35 | |||
36 | ret = pci_request_regions(pdev, DRV_NAME); | ||
37 | if (ret) | ||
38 | goto error; | ||
39 | |||
40 | p->register_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0)); | ||
41 | if (!p->register_base) { | ||
42 | ret = -EINVAL; | ||
43 | goto error; | ||
44 | } | ||
45 | |||
46 | p->regs.config = 0x1000; | ||
47 | p->regs.status = 0x1008; | ||
48 | p->regs.tx = 0x1010; | ||
49 | p->regs.data = 0x1080; | ||
50 | |||
51 | p->clk = devm_clk_get(dev, NULL); | ||
52 | if (IS_ERR(p->clk)) { | ||
53 | ret = PTR_ERR(p->clk); | ||
54 | goto error; | ||
55 | } | ||
56 | |||
57 | ret = clk_prepare_enable(p->clk); | ||
58 | if (ret) | ||
59 | goto error; | ||
60 | |||
61 | p->sys_freq = clk_get_rate(p->clk); | ||
62 | if (!p->sys_freq) | ||
63 | p->sys_freq = SYS_FREQ_DEFAULT; | ||
64 | dev_info(dev, "Set system clock to %u\n", p->sys_freq); | ||
65 | |||
66 | master->num_chipselect = 4; | ||
67 | master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | | ||
68 | SPI_LSB_FIRST | SPI_3WIRE; | ||
69 | master->transfer_one_message = octeon_spi_transfer_one_message; | ||
70 | master->bits_per_word_mask = SPI_BPW_MASK(8); | ||
71 | master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; | ||
72 | master->dev.of_node = pdev->dev.of_node; | ||
73 | |||
74 | pci_set_drvdata(pdev, master); | ||
75 | |||
76 | ret = devm_spi_register_master(dev, master); | ||
77 | if (ret) | ||
78 | goto error; | ||
79 | |||
80 | return 0; | ||
81 | |||
82 | error: | ||
83 | spi_master_put(master); | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static void thunderx_spi_remove(struct pci_dev *pdev) | ||
88 | { | ||
89 | struct spi_master *master = pci_get_drvdata(pdev); | ||
90 | struct octeon_spi *p; | ||
91 | |||
92 | p = spi_master_get_devdata(master); | ||
93 | if (!p) | ||
94 | return; | ||
95 | |||
96 | /* Put everything in a known state. */ | ||
97 | writeq(0, p->register_base + OCTEON_SPI_CFG(p)); | ||
98 | } | ||
99 | |||
100 | static const struct pci_device_id thunderx_spi_pci_id_table[] = { | ||
101 | { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa00b) }, | ||
102 | { 0, } | ||
103 | }; | ||
104 | |||
105 | MODULE_DEVICE_TABLE(pci, thunderx_spi_pci_id_table); | ||
106 | |||
107 | static struct pci_driver thunderx_spi_driver = { | ||
108 | .name = DRV_NAME, | ||
109 | .id_table = thunderx_spi_pci_id_table, | ||
110 | .probe = thunderx_spi_probe, | ||
111 | .remove = thunderx_spi_remove, | ||
112 | }; | ||
113 | |||
114 | module_pci_driver(thunderx_spi_driver); | ||
115 | |||
116 | MODULE_DESCRIPTION("Cavium, Inc. ThunderX SPI bus driver"); | ||
117 | MODULE_AUTHOR("Jan Glauber"); | ||
118 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/spi/spi-cavium.h b/drivers/spi/spi-cavium.h index 88c5f36e7ea7..1f91d61b745b 100644 --- a/drivers/spi/spi-cavium.h +++ b/drivers/spi/spi-cavium.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef __SPI_CAVIUM_H | 1 | #ifndef __SPI_CAVIUM_H |
2 | #define __SPI_CAVIUM_H | 2 | #define __SPI_CAVIUM_H |
3 | 3 | ||
4 | #include <linux/clk.h> | ||
5 | |||
4 | #define OCTEON_SPI_MAX_BYTES 9 | 6 | #define OCTEON_SPI_MAX_BYTES 9 |
5 | #define OCTEON_SPI_MAX_CLOCK_HZ 16000000 | 7 | #define OCTEON_SPI_MAX_CLOCK_HZ 16000000 |
6 | 8 | ||
@@ -17,6 +19,7 @@ struct octeon_spi { | |||
17 | u64 cs_enax; | 19 | u64 cs_enax; |
18 | int sys_freq; | 20 | int sys_freq; |
19 | struct octeon_spi_regs regs; | 21 | struct octeon_spi_regs regs; |
22 | struct clk *clk; | ||
20 | }; | 23 | }; |
21 | 24 | ||
22 | #define OCTEON_SPI_CFG(x) (x->regs.config) | 25 | #define OCTEON_SPI_CFG(x) (x->regs.config) |