mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04: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
10 changed files with 1989 additions and 15 deletions
|
|
@ -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 a new issue