mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 01:51:34 +00:00
Merge remote-tracking branches 'spi/topic/bcm', 'spi/topic/dw' and 'spi/topic/fsl-dspi' into spi-next
This commit is contained in:
commit
a931a189d4
233
Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt
Normal file
233
Documentation/devicetree/bindings/spi/brcm,spi-bcm-qspi.txt
Normal file
@ -0,0 +1,233 @@
|
||||
Broadcom SPI controller
|
||||
|
||||
The Broadcom SPI controller is a SPI master found on various SOCs, including
|
||||
BRCMSTB (BCM7XXX), Cygnus, NSP and NS2. The Broadcom Master SPI hw IP consits
|
||||
of :
|
||||
MSPI : SPI master controller can read and write to a SPI slave device
|
||||
BSPI : Broadcom SPI in combination with the MSPI hw IP provides acceleration
|
||||
for flash reads and be configured to do single, double, quad lane
|
||||
io with 3-byte and 4-byte addressing support.
|
||||
|
||||
Supported Broadcom SoCs have one instance of MSPI+BSPI controller IP.
|
||||
MSPI master can be used wihout BSPI. BRCMSTB SoCs have an additional instance
|
||||
of a MSPI master without the BSPI to use with non flash slave devices that
|
||||
use SPI protocol.
|
||||
|
||||
Required properties:
|
||||
|
||||
- #address-cells:
|
||||
Must be <1>, as required by generic SPI binding.
|
||||
|
||||
- #size-cells:
|
||||
Must be <0>, also as required by generic SPI binding.
|
||||
|
||||
- compatible:
|
||||
Must be one of :
|
||||
"brcm,spi-bcm-qspi", "brcm,spi-brcmstb-qspi" : MSPI+BSPI on BRCMSTB SoCs
|
||||
"brcm,spi-bcm-qspi", "brcm,spi-brcmstb-mspi" : Second Instance of MSPI
|
||||
BRCMSTB SoCs
|
||||
"brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi" : MSPI+BSPI on Cygnus, NSP
|
||||
"brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi" : NS2 SoCs
|
||||
|
||||
- reg:
|
||||
Define the bases and ranges of the associated I/O address spaces.
|
||||
The required range is MSPI controller registers.
|
||||
|
||||
- reg-names:
|
||||
First name does not matter, but must be reserved for the MSPI controller
|
||||
register range as mentioned in 'reg' above, and will typically contain
|
||||
- "bspi_regs": BSPI register range, not required with compatible
|
||||
"spi-brcmstb-mspi"
|
||||
- "mspi_regs": MSPI register range is required for compatible strings
|
||||
- "intr_regs", "intr_status_reg" : Interrupt and status register for
|
||||
NSP, NS2, Cygnus SoC
|
||||
|
||||
- interrupts
|
||||
The interrupts used by the MSPI and/or BSPI controller.
|
||||
|
||||
- interrupt-names:
|
||||
Names of interrupts associated with MSPI
|
||||
- "mspi_halted" :
|
||||
- "mspi_done": Indicates that the requested SPI operation is complete.
|
||||
- "spi_lr_fullness_reached" : Linear read BSPI pipe full
|
||||
- "spi_lr_session_aborted" : Linear read BSPI pipe aborted
|
||||
- "spi_lr_impatient" : Linear read BSPI requested when pipe empty
|
||||
- "spi_lr_session_done" : Linear read BSPI session done
|
||||
|
||||
- clocks:
|
||||
A phandle to the reference clock for this block.
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
||||
- native-endian
|
||||
Defined when using BE SoC and device uses BE register read/write
|
||||
|
||||
Recommended optional m25p80 properties:
|
||||
- spi-rx-bus-width: Definition as per
|
||||
Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
||||
Examples:
|
||||
|
||||
BRCMSTB SoC Example:
|
||||
|
||||
SPI Master (MSPI+BSPI) for SPI-NOR access:
|
||||
|
||||
spi@f03e3400 {
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x0>;
|
||||
compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-brcmstb-qspi";
|
||||
reg = <0xf03e0920 0x4 0xf03e3400 0x188 0xf03e3200 0x50>;
|
||||
reg-names = "cs_reg", "mspi", "bspi";
|
||||
interrupts = <0x6 0x5 0x4 0x3 0x2 0x1 0x0>;
|
||||
interrupt-parent = <0x1c>;
|
||||
interrupt-names = "mspi_halted",
|
||||
"mspi_done",
|
||||
"spi_lr_overread",
|
||||
"spi_lr_session_done",
|
||||
"spi_lr_impatient",
|
||||
"spi_lr_session_aborted",
|
||||
"spi_lr_fullness_reached";
|
||||
|
||||
clocks = <&hif_spi>;
|
||||
clock-names = "sw_spi";
|
||||
|
||||
m25p80@0 {
|
||||
#size-cells = <0x2>;
|
||||
#address-cells = <0x2>;
|
||||
compatible = "m25p80";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <0x2625a00>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
m25p,fast-read;
|
||||
|
||||
flash0.bolt@0 {
|
||||
reg = <0x0 0x0 0x0 0x100000>;
|
||||
};
|
||||
|
||||
flash0.macadr@100000 {
|
||||
reg = <0x0 0x100000 0x0 0x10000>;
|
||||
};
|
||||
|
||||
flash0.nvram@110000 {
|
||||
reg = <0x0 0x110000 0x0 0x10000>;
|
||||
};
|
||||
|
||||
flash0.kernel@120000 {
|
||||
reg = <0x0 0x120000 0x0 0x400000>;
|
||||
};
|
||||
|
||||
flash0.devtree@520000 {
|
||||
reg = <0x0 0x520000 0x0 0x10000>;
|
||||
};
|
||||
|
||||
flash0.splash@530000 {
|
||||
reg = <0x0 0x530000 0x0 0x80000>;
|
||||
};
|
||||
|
||||
flash0@0 {
|
||||
reg = <0x0 0x0 0x0 0x4000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
MSPI master for any SPI device :
|
||||
|
||||
spi@f0416000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&upg_fixed>;
|
||||
compatible = "brcm,spi-brcmstb-qspi", "brcm,spi-brcmstb-mspi";
|
||||
reg = <0xf0416000 0x180>;
|
||||
reg-names = "mspi";
|
||||
interrupts = <0x14>;
|
||||
interrupt-parent = <&irq0_aon_intc>;
|
||||
interrupt-names = "mspi_done";
|
||||
};
|
||||
|
||||
iProc SoC Example:
|
||||
|
||||
qspi: spi@18027200 {
|
||||
compatible = "brcm,spi-bcm-qspi", "brcm,spi-nsp-qspi";
|
||||
reg = <0x18027200 0x184>,
|
||||
<0x18027000 0x124>,
|
||||
<0x1811c408 0x004>,
|
||||
<0x180273a0 0x01c>;
|
||||
reg-names = "mspi_regs", "bspi_regs", "intr_regs", "intr_status_reg";
|
||||
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names =
|
||||
"spi_lr_fullness_reached",
|
||||
"spi_lr_session_aborted",
|
||||
"spi_lr_impatient",
|
||||
"spi_lr_session_done",
|
||||
"mspi_done",
|
||||
"mspi_halted";
|
||||
clocks = <&iprocmed>;
|
||||
clock-names = "iprocmed";
|
||||
num-cs = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
|
||||
NS2 SoC Example:
|
||||
|
||||
qspi: spi@66470200 {
|
||||
compatible = "brcm,spi-bcm-qspi", "brcm,spi-ns2-qspi";
|
||||
reg = <0x66470200 0x184>,
|
||||
<0x66470000 0x124>,
|
||||
<0x67017408 0x004>,
|
||||
<0x664703a0 0x01c>;
|
||||
reg-names = "mspi", "bspi", "intr_regs",
|
||||
"intr_status_reg";
|
||||
interrupts = <GIC_SPI 419 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "spi_l1_intr";
|
||||
clocks = <&iprocmed>;
|
||||
clock-names = "iprocmed";
|
||||
num-cs = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
|
||||
m25p80 node for NSP, NS2
|
||||
|
||||
&qspi {
|
||||
flash: m25p80@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "m25p80";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <12500000>;
|
||||
m25p,fast-read;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
|
||||
partition@0 {
|
||||
label = "boot";
|
||||
reg = <0x00000000 0x000a0000>;
|
||||
};
|
||||
|
||||
partition@a0000 {
|
||||
label = "env";
|
||||
reg = <0x000a0000 0x00060000>;
|
||||
};
|
||||
|
||||
partition@100000 {
|
||||
label = "system";
|
||||
reg = <0x00100000 0x00600000>;
|
||||
};
|
||||
|
||||
partition@700000 {
|
||||
label = "rootfs";
|
||||
reg = <0x00700000 0x01900000>;
|
||||
};
|
||||
};
|
@ -153,6 +153,16 @@ config SPI_BCM63XX_HSSPI
|
||||
This enables support for the High Speed SPI controller present on
|
||||
newer Broadcom BCM63XX SoCs.
|
||||
|
||||
config SPI_BCM_QSPI
|
||||
tristate "Broadcom BSPI and MSPI controller support"
|
||||
depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST
|
||||
default ARCH_BCM_IPROC
|
||||
help
|
||||
Enables support for the Broadcom SPI flash and MSPI controller.
|
||||
Select this option for any one of BRCMSTB, iProc NSP and NS2 SoCs
|
||||
based platforms. This driver works for both SPI master for spi-nor
|
||||
flash device as well as MSPI device.
|
||||
|
||||
config SPI_BITBANG
|
||||
tristate "Utilities for Bitbanging SPI masters"
|
||||
help
|
||||
|
@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_BCM2835AUX) += spi-bcm2835aux.o
|
||||
obj-$(CONFIG_SPI_BCM53XX) += spi-bcm53xx.o
|
||||
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
|
||||
obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
|
||||
obj-$(CONFIG_SPI_BCM_QSPI) += spi-iproc-qspi.o spi-brcmstb-qspi.o spi-bcm-qspi.o
|
||||
obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
|
||||
obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o
|
||||
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
|
||||
|
1397
drivers/spi/spi-bcm-qspi.c
Normal file
1397
drivers/spi/spi-bcm-qspi.c
Normal file
File diff suppressed because it is too large
Load Diff
115
drivers/spi/spi-bcm-qspi.h
Normal file
115
drivers/spi/spi-bcm-qspi.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2016 Broadcom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation (the "GPL").
|
||||
*
|
||||
* This program is distributed in the hope that 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 version 2 (GPLv2) for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 (GPLv2) along with this source code.
|
||||
*/
|
||||
|
||||
#ifndef __SPI_BCM_QSPI_H__
|
||||
#define __SPI_BCM_QSPI_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
/* BSPI interrupt masks */
|
||||
#define INTR_BSPI_LR_OVERREAD_MASK BIT(4)
|
||||
#define INTR_BSPI_LR_SESSION_DONE_MASK BIT(3)
|
||||
#define INTR_BSPI_LR_IMPATIENT_MASK BIT(2)
|
||||
#define INTR_BSPI_LR_SESSION_ABORTED_MASK BIT(1)
|
||||
#define INTR_BSPI_LR_FULLNESS_REACHED_MASK BIT(0)
|
||||
|
||||
#define BSPI_LR_INTERRUPTS_DATA \
|
||||
(INTR_BSPI_LR_SESSION_DONE_MASK | \
|
||||
INTR_BSPI_LR_FULLNESS_REACHED_MASK)
|
||||
|
||||
#define BSPI_LR_INTERRUPTS_ERROR \
|
||||
(INTR_BSPI_LR_OVERREAD_MASK | \
|
||||
INTR_BSPI_LR_IMPATIENT_MASK | \
|
||||
INTR_BSPI_LR_SESSION_ABORTED_MASK)
|
||||
|
||||
#define BSPI_LR_INTERRUPTS_ALL \
|
||||
(BSPI_LR_INTERRUPTS_ERROR | \
|
||||
BSPI_LR_INTERRUPTS_DATA)
|
||||
|
||||
/* MSPI Interrupt masks */
|
||||
#define INTR_MSPI_HALTED_MASK BIT(6)
|
||||
#define INTR_MSPI_DONE_MASK BIT(5)
|
||||
|
||||
#define MSPI_INTERRUPTS_ALL \
|
||||
(INTR_MSPI_DONE_MASK | \
|
||||
INTR_MSPI_HALTED_MASK)
|
||||
|
||||
#define QSPI_INTERRUPTS_ALL \
|
||||
(MSPI_INTERRUPTS_ALL | \
|
||||
BSPI_LR_INTERRUPTS_ALL)
|
||||
|
||||
struct platform_device;
|
||||
struct dev_pm_ops;
|
||||
|
||||
enum {
|
||||
MSPI_DONE = 0x1,
|
||||
BSPI_DONE = 0x2,
|
||||
BSPI_ERR = 0x4,
|
||||
MSPI_BSPI_DONE = 0x7
|
||||
};
|
||||
|
||||
struct bcm_qspi_soc_intc {
|
||||
void (*bcm_qspi_int_ack)(struct bcm_qspi_soc_intc *soc_intc, int type);
|
||||
void (*bcm_qspi_int_set)(struct bcm_qspi_soc_intc *soc_intc, int type,
|
||||
bool en);
|
||||
u32 (*bcm_qspi_get_int_status)(struct bcm_qspi_soc_intc *soc_intc);
|
||||
};
|
||||
|
||||
/* Read controller register*/
|
||||
static inline u32 bcm_qspi_readl(bool be, void __iomem *addr)
|
||||
{
|
||||
if (be)
|
||||
return ioread32be(addr);
|
||||
else
|
||||
return readl_relaxed(addr);
|
||||
}
|
||||
|
||||
/* Write controller register*/
|
||||
static inline void bcm_qspi_writel(bool be,
|
||||
unsigned int data, void __iomem *addr)
|
||||
{
|
||||
if (be)
|
||||
iowrite32be(data, addr);
|
||||
else
|
||||
writel_relaxed(data, addr);
|
||||
}
|
||||
|
||||
static inline u32 get_qspi_mask(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case MSPI_DONE:
|
||||
return INTR_MSPI_DONE_MASK;
|
||||
case BSPI_DONE:
|
||||
return BSPI_LR_INTERRUPTS_ALL;
|
||||
case MSPI_BSPI_DONE:
|
||||
return QSPI_INTERRUPTS_ALL;
|
||||
case BSPI_ERR:
|
||||
return BSPI_LR_INTERRUPTS_ERROR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The common driver functions to be called by the SoC platform driver */
|
||||
int bcm_qspi_probe(struct platform_device *pdev,
|
||||
struct bcm_qspi_soc_intc *soc_intc);
|
||||
int bcm_qspi_remove(struct platform_device *pdev);
|
||||
|
||||
/* pm_ops used by the SoC platform driver called on PM suspend/resume */
|
||||
extern const struct dev_pm_ops bcm_qspi_pm_ops;
|
||||
|
||||
#endif /* __SPI_BCM_QSPI_H__ */
|
53
drivers/spi/spi-brcmstb-qspi.c
Normal file
53
drivers/spi/spi-brcmstb-qspi.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2016 Broadcom
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation (the "GPL").
|
||||
*
|
||||
* This program is distributed in the hope that 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 version 2 (GPLv2) for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 (GPLv2) along with this source code.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include "spi-bcm-qspi.h"
|
||||
|
||||
static const struct of_device_id brcmstb_qspi_of_match[] = {
|
||||
{ .compatible = "brcm,spi-brcmstb-qspi" },
|
||||
{ .compatible = "brcm,spi-brcmstb-mspi" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, brcmstb_qspi_of_match);
|
||||
|
||||
static int brcmstb_qspi_probe(struct platform_device *pdev)
|
||||
{
|
||||
return bcm_qspi_probe(pdev, NULL);
|
||||
}
|
||||
|
||||
static int brcmstb_qspi_remove(struct platform_device *pdev)
|
||||
{
|
||||
return bcm_qspi_remove(pdev);
|
||||
}
|
||||
|
||||
static struct platform_driver brcmstb_qspi_driver = {
|
||||
.probe = brcmstb_qspi_probe,
|
||||
.remove = brcmstb_qspi_remove,
|
||||
.driver = {
|
||||
.name = "brcmstb_qspi",
|
||||
.pm = &bcm_qspi_pm_ops,
|
||||
.of_match_table = brcmstb_qspi_of_match,
|
||||
}
|
||||
};
|
||||
module_platform_driver(brcmstb_qspi_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Kamal Dasu");
|
||||
MODULE_DESCRIPTION("Broadcom SPI driver for settop SoC");
|
@ -283,7 +283,6 @@ static int dw_spi_transfer_one(struct spi_master *master,
|
||||
struct chip_data *chip = spi_get_ctldata(spi);
|
||||
u8 imask = 0;
|
||||
u16 txlevel = 0;
|
||||
u16 clk_div;
|
||||
u32 cr0;
|
||||
int ret;
|
||||
|
||||
@ -298,13 +297,13 @@ static int dw_spi_transfer_one(struct spi_master *master,
|
||||
spi_enable_chip(dws, 0);
|
||||
|
||||
/* Handle per transfer options for bpw and speed */
|
||||
if (transfer->speed_hz != chip->speed_hz) {
|
||||
/* clk_div doesn't support odd number */
|
||||
clk_div = (dws->max_freq / transfer->speed_hz + 1) & 0xfffe;
|
||||
|
||||
chip->speed_hz = transfer->speed_hz;
|
||||
chip->clk_div = clk_div;
|
||||
|
||||
if (transfer->speed_hz != dws->current_freq) {
|
||||
if (transfer->speed_hz != chip->speed_hz) {
|
||||
/* clk_div doesn't support odd number */
|
||||
chip->clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe;
|
||||
chip->speed_hz = transfer->speed_hz;
|
||||
}
|
||||
dws->current_freq = transfer->speed_hz;
|
||||
spi_set_clk(dws, chip->clk_div);
|
||||
}
|
||||
if (transfer->bits_per_word == 8) {
|
||||
|
@ -123,6 +123,7 @@ struct dw_spi {
|
||||
u8 n_bytes; /* current is a 1/2 bytes op */
|
||||
u32 dma_width;
|
||||
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
|
||||
u32 current_freq; /* frequency in hz */
|
||||
|
||||
/* DMA info */
|
||||
int dma_inited;
|
||||
|
@ -159,7 +159,7 @@ struct fsl_dspi {
|
||||
u8 cs;
|
||||
u16 void_write_data;
|
||||
u32 cs_change;
|
||||
struct fsl_dspi_devtype_data *devtype_data;
|
||||
const struct fsl_dspi_devtype_data *devtype_data;
|
||||
|
||||
wait_queue_head_t waitq;
|
||||
u32 waitflags;
|
||||
@ -624,10 +624,13 @@ static int dspi_resume(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct fsl_dspi *dspi = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
clk_prepare_enable(dspi->clk);
|
||||
ret = clk_prepare_enable(dspi->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
spi_master_resume(master);
|
||||
|
||||
return 0;
|
||||
@ -651,8 +654,6 @@ static int dspi_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret = 0, cs_num, bus_num;
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(fsl_dspi_dt_ids, &pdev->dev);
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
|
||||
if (!master)
|
||||
@ -686,7 +687,7 @@ static int dspi_probe(struct platform_device *pdev)
|
||||
}
|
||||
master->bus_num = bus_num;
|
||||
|
||||
dspi->devtype_data = (struct fsl_dspi_devtype_data *)of_id->data;
|
||||
dspi->devtype_data = of_device_get_match_data(&pdev->dev);
|
||||
if (!dspi->devtype_data) {
|
||||
dev_err(&pdev->dev, "can't get devtype_data\n");
|
||||
ret = -EFAULT;
|
||||
@ -728,7 +729,9 @@ static int dspi_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev, "unable to get clock\n");
|
||||
goto out_master_put;
|
||||
}
|
||||
clk_prepare_enable(dspi->clk);
|
||||
ret = clk_prepare_enable(dspi->clk);
|
||||
if (ret)
|
||||
goto out_master_put;
|
||||
|
||||
master->max_speed_hz =
|
||||
clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor;
|
||||
@ -760,7 +763,6 @@ static int dspi_remove(struct platform_device *pdev)
|
||||
/* Disconnect from the SPI framework */
|
||||
clk_disable_unprepare(dspi->clk);
|
||||
spi_unregister_master(dspi->master);
|
||||
spi_master_put(dspi->master);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
163
drivers/spi/spi-iproc-qspi.c
Normal file
163
drivers/spi/spi-iproc-qspi.c
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2016 Broadcom Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that 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.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "spi-bcm-qspi.h"
|
||||
|
||||
#define INTR_BASE_BIT_SHIFT 0x02
|
||||
#define INTR_COUNT 0x07
|
||||
|
||||
struct bcm_iproc_intc {
|
||||
struct bcm_qspi_soc_intc soc_intc;
|
||||
struct platform_device *pdev;
|
||||
void __iomem *int_reg;
|
||||
void __iomem *int_status_reg;
|
||||
spinlock_t soclock;
|
||||
bool big_endian;
|
||||
};
|
||||
|
||||
static u32 bcm_iproc_qspi_get_l2_int_status(struct bcm_qspi_soc_intc *soc_intc)
|
||||
{
|
||||
struct bcm_iproc_intc *priv =
|
||||
container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
|
||||
void __iomem *mmio = priv->int_status_reg;
|
||||
int i;
|
||||
u32 val = 0, sts = 0;
|
||||
|
||||
for (i = 0; i < INTR_COUNT; i++) {
|
||||
if (bcm_qspi_readl(priv->big_endian, mmio + (i * 4)))
|
||||
val |= 1UL << i;
|
||||
}
|
||||
|
||||
if (val & INTR_MSPI_DONE_MASK)
|
||||
sts |= MSPI_DONE;
|
||||
|
||||
if (val & BSPI_LR_INTERRUPTS_ALL)
|
||||
sts |= BSPI_DONE;
|
||||
|
||||
if (val & BSPI_LR_INTERRUPTS_ERROR)
|
||||
sts |= BSPI_ERR;
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
static void bcm_iproc_qspi_int_ack(struct bcm_qspi_soc_intc *soc_intc, int type)
|
||||
{
|
||||
struct bcm_iproc_intc *priv =
|
||||
container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
|
||||
void __iomem *mmio = priv->int_status_reg;
|
||||
u32 mask = get_qspi_mask(type);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < INTR_COUNT; i++) {
|
||||
if (mask & (1UL << i))
|
||||
bcm_qspi_writel(priv->big_endian, 1, mmio + (i * 4));
|
||||
}
|
||||
}
|
||||
|
||||
static void bcm_iproc_qspi_int_set(struct bcm_qspi_soc_intc *soc_intc, int type,
|
||||
bool en)
|
||||
{
|
||||
struct bcm_iproc_intc *priv =
|
||||
container_of(soc_intc, struct bcm_iproc_intc, soc_intc);
|
||||
void __iomem *mmio = priv->int_reg;
|
||||
u32 mask = get_qspi_mask(type);
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->soclock, flags);
|
||||
|
||||
val = bcm_qspi_readl(priv->big_endian, mmio);
|
||||
|
||||
if (en)
|
||||
val = val | (mask << INTR_BASE_BIT_SHIFT);
|
||||
else
|
||||
val = val & ~(mask << INTR_BASE_BIT_SHIFT);
|
||||
|
||||
bcm_qspi_writel(priv->big_endian, val, mmio);
|
||||
|
||||
spin_unlock_irqrestore(&priv->soclock, flags);
|
||||
}
|
||||
|
||||
static int bcm_iproc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct bcm_iproc_intc *priv;
|
||||
struct bcm_qspi_soc_intc *soc_intc;
|
||||
struct resource *res;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
soc_intc = &priv->soc_intc;
|
||||
priv->pdev = pdev;
|
||||
|
||||
spin_lock_init(&priv->soclock);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr_regs");
|
||||
priv->int_reg = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->int_reg))
|
||||
return PTR_ERR(priv->int_reg);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"intr_status_reg");
|
||||
priv->int_status_reg = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->int_status_reg))
|
||||
return PTR_ERR(priv->int_status_reg);
|
||||
|
||||
priv->big_endian = of_device_is_big_endian(dev->of_node);
|
||||
|
||||
bcm_iproc_qspi_int_ack(soc_intc, MSPI_BSPI_DONE);
|
||||
bcm_iproc_qspi_int_set(soc_intc, MSPI_BSPI_DONE, false);
|
||||
|
||||
soc_intc->bcm_qspi_int_ack = bcm_iproc_qspi_int_ack;
|
||||
soc_intc->bcm_qspi_int_set = bcm_iproc_qspi_int_set;
|
||||
soc_intc->bcm_qspi_get_int_status = bcm_iproc_qspi_get_l2_int_status;
|
||||
|
||||
return bcm_qspi_probe(pdev, soc_intc);
|
||||
}
|
||||
|
||||
static int bcm_iproc_remove(struct platform_device *pdev)
|
||||
{
|
||||
return bcm_qspi_remove(pdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm_iproc_of_match[] = {
|
||||
{ .compatible = "brcm,spi-nsp-qspi" },
|
||||
{ .compatible = "brcm,spi-ns2-qspi" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bcm_iproc_of_match);
|
||||
|
||||
static struct platform_driver bcm_iproc_driver = {
|
||||
.probe = bcm_iproc_probe,
|
||||
.remove = bcm_iproc_remove,
|
||||
.driver = {
|
||||
.name = "bcm_iproc",
|
||||
.pm = &bcm_qspi_pm_ops,
|
||||
.of_match_table = bcm_iproc_of_match,
|
||||
}
|
||||
};
|
||||
module_platform_driver(bcm_iproc_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Kamal Dasu");
|
||||
MODULE_DESCRIPTION("SPI flash driver for Broadcom iProc SoCs");
|
Loading…
Reference in New Issue
Block a user