mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-05-24 10:39:52 +00:00
Merge remote-tracking branches 'spi/topic/drivers', 'spi/topic/dw', 'spi/topic/efm32', 'spi/topic/ep93xx', 'spi/topic/fsl', 'spi/topic/fsl-dspi', 'spi/topic/fsl-espi' and 'spi/topic/gpio' into spi-next
This commit is contained in:
parent
9dee279b40
23e2c2aa45
c63f5da008
12f6dd860c
56fc0b42dc
7282326b72
0e0cd9ea89
f0a71337be
e1bde3b11f
commit
3bcbc14911
14 changed files with 117 additions and 128 deletions
|
@ -3,24 +3,24 @@
|
||||||
Required properties:
|
Required properties:
|
||||||
- #address-cells: see spi-bus.txt
|
- #address-cells: see spi-bus.txt
|
||||||
- #size-cells: see spi-bus.txt
|
- #size-cells: see spi-bus.txt
|
||||||
- compatible: should be "efm32,spi"
|
- compatible: should be "energymicro,efm32-spi"
|
||||||
- reg: Offset and length of the register set for the controller
|
- reg: Offset and length of the register set for the controller
|
||||||
- interrupts: pair specifying rx and tx irq
|
- interrupts: pair specifying rx and tx irq
|
||||||
- clocks: phandle to the spi clock
|
- clocks: phandle to the spi clock
|
||||||
- cs-gpios: see spi-bus.txt
|
- cs-gpios: see spi-bus.txt
|
||||||
- location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
|
- efm32,location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
spi1: spi@0x4000c400 { /* USART1 */
|
spi1: spi@0x4000c400 { /* USART1 */
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
compatible = "efm32,spi";
|
compatible = "energymicro,efm32-spi";
|
||||||
reg = <0x4000c400 0x400>;
|
reg = <0x4000c400 0x400>;
|
||||||
interrupts = <15 16>;
|
interrupts = <15 16>;
|
||||||
clocks = <&cmu 20>;
|
clocks = <&cmu 20>;
|
||||||
cs-gpios = <&gpio 51 1>; // D3
|
cs-gpios = <&gpio 51 1>; // D3
|
||||||
location = <1>;
|
efm32,location = <1>;
|
||||||
status = "ok";
|
status = "ok";
|
||||||
|
|
||||||
ks8851@0 {
|
ks8851@0 {
|
||||||
|
|
|
@ -10,6 +10,7 @@ Required properties:
|
||||||
- pinctrl-names: must contain a "default" entry.
|
- pinctrl-names: must contain a "default" entry.
|
||||||
- spi-num-chipselects : the number of the chipselect signals.
|
- spi-num-chipselects : the number of the chipselect signals.
|
||||||
- bus-num : the slave chip chipselect signal number.
|
- bus-num : the slave chip chipselect signal number.
|
||||||
|
- big-endian : if DSPI modudle is big endian, the bool will be set in node.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
dspi0@4002c000 {
|
dspi0@4002c000 {
|
||||||
|
@ -24,6 +25,7 @@ dspi0@4002c000 {
|
||||||
bus-num = <0>;
|
bus-num = <0>;
|
||||||
pinctrl-names = "default";
|
pinctrl-names = "default";
|
||||||
pinctrl-0 = <&pinctrl_dspi0_1>;
|
pinctrl-0 = <&pinctrl_dspi0_1>;
|
||||||
|
big-endian;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
||||||
sflash: at26df081a@0 {
|
sflash: at26df081a@0 {
|
||||||
|
|
|
@ -270,6 +270,7 @@ config SPI_FSL_SPI
|
||||||
config SPI_FSL_DSPI
|
config SPI_FSL_DSPI
|
||||||
tristate "Freescale DSPI controller"
|
tristate "Freescale DSPI controller"
|
||||||
select SPI_BITBANG
|
select SPI_BITBANG
|
||||||
|
select REGMAP_MMIO
|
||||||
depends on SOC_VF610 || COMPILE_TEST
|
depends on SOC_VF610 || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This enables support for the Freescale DSPI controller in master
|
This enables support for the Freescale DSPI controller in master
|
||||||
|
@ -546,7 +547,7 @@ config SPI_DW_MID_DMA
|
||||||
|
|
||||||
config SPI_DW_MMIO
|
config SPI_DW_MMIO
|
||||||
tristate "Memory-mapped io interface driver for DW SPI core"
|
tristate "Memory-mapped io interface driver for DW SPI core"
|
||||||
depends on SPI_DESIGNWARE && HAVE_CLK
|
depends on SPI_DESIGNWARE
|
||||||
|
|
||||||
#
|
#
|
||||||
# There are lots of SPI device types, with sensors and memory
|
# There are lots of SPI device types, with sensors and memory
|
||||||
|
|
|
@ -66,7 +66,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
dws->bus_num = 0;
|
dws->bus_num = pdev->id;
|
||||||
dws->num_cs = 4;
|
dws->num_cs = 4;
|
||||||
dws->max_freq = clk_get_rate(dwsmmio->clk);
|
dws->max_freq = clk_get_rate(dwsmmio->clk);
|
||||||
|
|
||||||
|
|
|
@ -276,8 +276,7 @@ static void giveback(struct dw_spi *dws)
|
||||||
queue_work(dws->workqueue, &dws->pump_messages);
|
queue_work(dws->workqueue, &dws->pump_messages);
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
spin_unlock_irqrestore(&dws->lock, flags);
|
||||||
|
|
||||||
last_transfer = list_entry(msg->transfers.prev,
|
last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
|
||||||
struct spi_transfer,
|
|
||||||
transfer_list);
|
transfer_list);
|
||||||
|
|
||||||
if (!last_transfer->cs_change && dws->cs_control)
|
if (!last_transfer->cs_change && dws->cs_control)
|
||||||
|
@ -439,12 +438,6 @@ static void pump_transfers(unsigned long data)
|
||||||
|
|
||||||
if (transfer->speed_hz != speed) {
|
if (transfer->speed_hz != speed) {
|
||||||
speed = transfer->speed_hz;
|
speed = transfer->speed_hz;
|
||||||
if (speed > dws->max_freq) {
|
|
||||||
printk(KERN_ERR "MRST SPI0: unsupported"
|
|
||||||
"freq: %dHz\n", speed);
|
|
||||||
message->status = -EIO;
|
|
||||||
goto early_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clk_div doesn't support odd number */
|
/* clk_div doesn't support odd number */
|
||||||
clk_div = dws->max_freq / speed;
|
clk_div = dws->max_freq / speed;
|
||||||
|
@ -671,12 +664,6 @@ static int dw_spi_setup(struct spi_device *spi)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dw_spi_cleanup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
struct chip_data *chip = spi_get_ctldata(spi);
|
|
||||||
kfree(chip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int init_queue(struct dw_spi *dws)
|
static int init_queue(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
INIT_LIST_HEAD(&dws->queue);
|
INIT_LIST_HEAD(&dws->queue);
|
||||||
|
@ -806,9 +793,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
||||||
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||||
master->bus_num = dws->bus_num;
|
master->bus_num = dws->bus_num;
|
||||||
master->num_chipselect = dws->num_cs;
|
master->num_chipselect = dws->num_cs;
|
||||||
master->cleanup = dw_spi_cleanup;
|
|
||||||
master->setup = dw_spi_setup;
|
master->setup = dw_spi_setup;
|
||||||
master->transfer = dw_spi_transfer;
|
master->transfer = dw_spi_transfer;
|
||||||
|
master->max_speed_hz = dws->max_freq;
|
||||||
|
|
||||||
/* Basic HW init */
|
/* Basic HW init */
|
||||||
spi_hw_init(dws);
|
spi_hw_init(dws);
|
||||||
|
|
|
@ -287,17 +287,17 @@ static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
|
||||||
return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
|
return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int efm32_spi_probe_dt(struct platform_device *pdev,
|
static void efm32_spi_probe_dt(struct platform_device *pdev,
|
||||||
struct spi_master *master, struct efm32_spi_ddata *ddata)
|
struct spi_master *master, struct efm32_spi_ddata *ddata)
|
||||||
{
|
{
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
u32 location;
|
u32 location;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!np)
|
ret = of_property_read_u32(np, "efm32,location", &location);
|
||||||
return 1;
|
if (ret)
|
||||||
|
/* fall back to old and (wrongly) generic property "location" */
|
||||||
ret = of_property_read_u32(np, "location", &location);
|
ret = of_property_read_u32(np, "location", &location);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
dev_dbg(&pdev->dev, "using location %u\n", location);
|
dev_dbg(&pdev->dev, "using location %u\n", location);
|
||||||
} else {
|
} else {
|
||||||
|
@ -308,7 +308,6 @@ static int efm32_spi_probe_dt(struct platform_device *pdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
ddata->pdata.location = location;
|
ddata->pdata.location = location;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int efm32_spi_probe(struct platform_device *pdev)
|
static int efm32_spi_probe(struct platform_device *pdev)
|
||||||
|
@ -318,9 +317,14 @@ static int efm32_spi_probe(struct platform_device *pdev)
|
||||||
int ret;
|
int ret;
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
unsigned int num_cs, i;
|
int num_cs, i;
|
||||||
|
|
||||||
|
if (!np)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
num_cs = of_gpio_named_count(np, "cs-gpios");
|
num_cs = of_gpio_named_count(np, "cs-gpios");
|
||||||
|
if (num_cs < 0)
|
||||||
|
return num_cs;
|
||||||
|
|
||||||
master = spi_alloc_master(&pdev->dev,
|
master = spi_alloc_master(&pdev->dev,
|
||||||
sizeof(*ddata) + num_cs * sizeof(unsigned));
|
sizeof(*ddata) + num_cs * sizeof(unsigned));
|
||||||
|
@ -412,23 +416,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = efm32_spi_probe_dt(pdev, master, ddata);
|
efm32_spi_probe_dt(pdev, master, ddata);
|
||||||
if (ret > 0) {
|
|
||||||
/* not created by device tree */
|
|
||||||
const struct efm32_spi_pdata *pdata =
|
|
||||||
dev_get_platdata(&pdev->dev);
|
|
||||||
|
|
||||||
if (pdata)
|
|
||||||
ddata->pdata = *pdata;
|
|
||||||
else
|
|
||||||
ddata->pdata.location =
|
|
||||||
efm32_spi_get_configured_location(ddata);
|
|
||||||
|
|
||||||
master->bus_num = pdev->id;
|
|
||||||
|
|
||||||
} else if (ret < 0) {
|
|
||||||
goto err_disable_clk;
|
|
||||||
}
|
|
||||||
|
|
||||||
efm32_spi_write32(ddata, 0, REG_IEN);
|
efm32_spi_write32(ddata, 0, REG_IEN);
|
||||||
efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
|
efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
|
||||||
|
@ -484,6 +472,9 @@ static int efm32_spi_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
static const struct of_device_id efm32_spi_dt_ids[] = {
|
static const struct of_device_id efm32_spi_dt_ids[] = {
|
||||||
{
|
{
|
||||||
|
.compatible = "energymicro,efm32-spi",
|
||||||
|
}, {
|
||||||
|
/* doesn't follow the "vendor,device" scheme, don't use */
|
||||||
.compatible = "efm32,spi",
|
.compatible = "efm32,spi",
|
||||||
}, {
|
}, {
|
||||||
/* sentinel */
|
/* sentinel */
|
||||||
|
|
|
@ -73,8 +73,6 @@
|
||||||
* @clk: clock for the controller
|
* @clk: clock for the controller
|
||||||
* @regs_base: pointer to ioremap()'d registers
|
* @regs_base: pointer to ioremap()'d registers
|
||||||
* @sspdr_phys: physical address of the SSPDR register
|
* @sspdr_phys: physical address of the SSPDR register
|
||||||
* @min_rate: minimum clock rate (in Hz) supported by the controller
|
|
||||||
* @max_rate: maximum clock rate (in Hz) supported by the controller
|
|
||||||
* @wait: wait here until given transfer is completed
|
* @wait: wait here until given transfer is completed
|
||||||
* @current_msg: message that is currently processed (or %NULL if none)
|
* @current_msg: message that is currently processed (or %NULL if none)
|
||||||
* @tx: current byte in transfer to transmit
|
* @tx: current byte in transfer to transmit
|
||||||
|
@ -95,8 +93,6 @@ struct ep93xx_spi {
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
void __iomem *regs_base;
|
void __iomem *regs_base;
|
||||||
unsigned long sspdr_phys;
|
unsigned long sspdr_phys;
|
||||||
unsigned long min_rate;
|
|
||||||
unsigned long max_rate;
|
|
||||||
struct completion wait;
|
struct completion wait;
|
||||||
struct spi_message *current_msg;
|
struct spi_message *current_msg;
|
||||||
size_t tx;
|
size_t tx;
|
||||||
|
@ -199,9 +195,9 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
|
||||||
* @div_scr: pointer to return the scr divider
|
* @div_scr: pointer to return the scr divider
|
||||||
*/
|
*/
|
||||||
static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
|
static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
|
||||||
unsigned long rate,
|
u32 rate, u8 *div_cpsr, u8 *div_scr)
|
||||||
u8 *div_cpsr, u8 *div_scr)
|
|
||||||
{
|
{
|
||||||
|
struct spi_master *master = platform_get_drvdata(espi->pdev);
|
||||||
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
|
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
|
||||||
int cpsr, scr;
|
int cpsr, scr;
|
||||||
|
|
||||||
|
@ -210,7 +206,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
|
||||||
* controller. Note that minimum value is already checked in
|
* controller. Note that minimum value is already checked in
|
||||||
* ep93xx_spi_transfer_one_message().
|
* ep93xx_spi_transfer_one_message().
|
||||||
*/
|
*/
|
||||||
rate = clamp(rate, espi->min_rate, espi->max_rate);
|
rate = clamp(rate, master->min_speed_hz, master->max_speed_hz);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate divisors so that we can get speed according the
|
* Calculate divisors so that we can get speed according the
|
||||||
|
@ -735,13 +731,6 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master,
|
||||||
struct spi_message *msg)
|
struct spi_message *msg)
|
||||||
{
|
{
|
||||||
struct ep93xx_spi *espi = spi_master_get_devdata(master);
|
struct ep93xx_spi *espi = spi_master_get_devdata(master);
|
||||||
struct spi_transfer *t;
|
|
||||||
|
|
||||||
/* first validate each transfer */
|
|
||||||
list_for_each_entry(t, &msg->transfers, transfer_list) {
|
|
||||||
if (t->speed_hz < espi->min_rate)
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg->state = NULL;
|
msg->state = NULL;
|
||||||
msg->status = 0;
|
msg->status = 0;
|
||||||
|
@ -917,8 +906,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
|
||||||
* Calculate maximum and minimum supported clock rates
|
* Calculate maximum and minimum supported clock rates
|
||||||
* for the controller.
|
* for the controller.
|
||||||
*/
|
*/
|
||||||
espi->max_rate = clk_get_rate(espi->clk) / 2;
|
master->max_speed_hz = clk_get_rate(espi->clk) / 2;
|
||||||
espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
|
master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
|
||||||
espi->pdev = pdev;
|
espi->pdev = pdev;
|
||||||
|
|
||||||
espi->sspdr_phys = res->start + SSPDR;
|
espi->sspdr_phys = res->start + SSPDR;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
@ -108,11 +109,11 @@ struct fsl_dspi {
|
||||||
struct spi_bitbang bitbang;
|
struct spi_bitbang bitbang;
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
|
|
||||||
void __iomem *base;
|
struct regmap *regmap;
|
||||||
int irq;
|
int irq;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
|
||||||
struct spi_transfer *cur_transfer;
|
struct spi_transfer *cur_transfer;
|
||||||
struct chip_data *cur_chip;
|
struct chip_data *cur_chip;
|
||||||
size_t len;
|
size_t len;
|
||||||
void *tx;
|
void *tx;
|
||||||
|
@ -123,24 +124,17 @@ struct fsl_dspi {
|
||||||
u8 cs;
|
u8 cs;
|
||||||
u16 void_write_data;
|
u16 void_write_data;
|
||||||
|
|
||||||
wait_queue_head_t waitq;
|
wait_queue_head_t waitq;
|
||||||
u32 waitflags;
|
u32 waitflags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int is_double_byte_mode(struct fsl_dspi *dspi)
|
static inline int is_double_byte_mode(struct fsl_dspi *dspi)
|
||||||
{
|
{
|
||||||
return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK)
|
unsigned int val;
|
||||||
== SPI_FRAME_BITS(8)) ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits)
|
regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val);
|
||||||
{
|
|
||||||
u32 temp;
|
|
||||||
|
|
||||||
temp = readl(dspi->base + SPI_CTAR(dspi->cs));
|
return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
|
||||||
temp &= ~SPI_FRAME_BITS_MASK;
|
|
||||||
temp |= SPI_FRAME_BITS(bits);
|
|
||||||
writel(temp, dspi->base + SPI_CTAR(dspi->cs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
|
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
|
||||||
|
@ -188,7 +182,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
|
||||||
*/
|
*/
|
||||||
if (tx_word && (dspi->len == 1)) {
|
if (tx_word && (dspi->len == 1)) {
|
||||||
dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
|
dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
|
||||||
set_bit_mode(dspi, 8);
|
regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
|
||||||
|
SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
|
||||||
tx_word = 0;
|
tx_word = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,7 +233,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
|
||||||
dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
|
dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
|
||||||
}
|
}
|
||||||
|
|
||||||
writel(dspi_pushr, dspi->base + SPI_PUSHR);
|
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
|
||||||
|
|
||||||
tx_count++;
|
tx_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,17 +249,23 @@ static int dspi_transfer_read(struct fsl_dspi *dspi)
|
||||||
while ((dspi->rx < dspi->rx_end)
|
while ((dspi->rx < dspi->rx_end)
|
||||||
&& (rx_count < DSPI_FIFO_SIZE)) {
|
&& (rx_count < DSPI_FIFO_SIZE)) {
|
||||||
if (rx_word) {
|
if (rx_word) {
|
||||||
|
unsigned int val;
|
||||||
|
|
||||||
if ((dspi->rx_end - dspi->rx) == 1)
|
if ((dspi->rx_end - dspi->rx) == 1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
|
regmap_read(dspi->regmap, SPI_POPR, &val);
|
||||||
|
d = SPI_POPR_RXDATA(val);
|
||||||
|
|
||||||
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
|
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
|
||||||
*(u16 *)dspi->rx = d;
|
*(u16 *)dspi->rx = d;
|
||||||
dspi->rx += 2;
|
dspi->rx += 2;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
|
unsigned int val;
|
||||||
|
|
||||||
|
regmap_read(dspi->regmap, SPI_POPR, &val);
|
||||||
|
d = SPI_POPR_RXDATA(val);
|
||||||
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
|
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
|
||||||
*(u8 *)dspi->rx = d;
|
*(u8 *)dspi->rx = d;
|
||||||
dspi->rx++;
|
dspi->rx++;
|
||||||
|
@ -295,13 +297,13 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||||
if (!dspi->tx)
|
if (!dspi->tx)
|
||||||
dspi->dataflags |= TRAN_STATE_TX_VOID;
|
dspi->dataflags |= TRAN_STATE_TX_VOID;
|
||||||
|
|
||||||
writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR);
|
regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
|
||||||
writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs));
|
regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val);
|
||||||
writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER);
|
regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
|
||||||
|
|
||||||
if (t->speed_hz)
|
if (t->speed_hz)
|
||||||
writel(dspi->cur_chip->ctar_val,
|
regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
|
||||||
dspi->base + SPI_CTAR(dspi->cs));
|
dspi->cur_chip->ctar_val);
|
||||||
|
|
||||||
dspi_transfer_write(dspi);
|
dspi_transfer_write(dspi);
|
||||||
|
|
||||||
|
@ -315,7 +317,9 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||||
static void dspi_chipselect(struct spi_device *spi, int value)
|
static void dspi_chipselect(struct spi_device *spi, int value)
|
||||||
{
|
{
|
||||||
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
|
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
|
||||||
u32 pushr = readl(dspi->base + SPI_PUSHR);
|
unsigned int pushr;
|
||||||
|
|
||||||
|
regmap_read(dspi->regmap, SPI_PUSHR, &pushr);
|
||||||
|
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case BITBANG_CS_ACTIVE:
|
case BITBANG_CS_ACTIVE:
|
||||||
|
@ -326,7 +330,7 @@ static void dspi_chipselect(struct spi_device *spi, int value)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
writel(pushr, dspi->base + SPI_PUSHR);
|
regmap_write(dspi->regmap, SPI_PUSHR, pushr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||||
|
@ -338,7 +342,8 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||||
/* Only alloc on first setup */
|
/* Only alloc on first setup */
|
||||||
chip = spi_get_ctldata(spi);
|
chip = spi_get_ctldata(spi);
|
||||||
if (chip == NULL) {
|
if (chip == NULL) {
|
||||||
chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
|
chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data),
|
||||||
|
GFP_KERNEL);
|
||||||
if (!chip)
|
if (!chip)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -349,7 +354,6 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||||
fmsz = spi->bits_per_word - 1;
|
fmsz = spi->bits_per_word - 1;
|
||||||
} else {
|
} else {
|
||||||
pr_err("Invalid wordsize\n");
|
pr_err("Invalid wordsize\n");
|
||||||
kfree(chip);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,13 +386,15 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
|
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
|
||||||
|
|
||||||
writel(SPI_SR_EOQF, dspi->base + SPI_SR);
|
regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF);
|
||||||
|
|
||||||
dspi_transfer_read(dspi);
|
dspi_transfer_read(dspi);
|
||||||
|
|
||||||
if (!dspi->len) {
|
if (!dspi->len) {
|
||||||
if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
|
if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
|
||||||
set_bit_mode(dspi, 16);
|
regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
|
||||||
|
SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16));
|
||||||
|
|
||||||
dspi->waitflags = 1;
|
dspi->waitflags = 1;
|
||||||
wake_up_interruptible(&dspi->waitq);
|
wake_up_interruptible(&dspi->waitq);
|
||||||
} else {
|
} else {
|
||||||
|
@ -430,8 +436,13 @@ static int dspi_resume(struct device *dev)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
static const struct dev_pm_ops dspi_pm = {
|
static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
|
||||||
SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume)
|
|
||||||
|
static struct regmap_config dspi_regmap_config = {
|
||||||
|
.reg_bits = 32,
|
||||||
|
.val_bits = 32,
|
||||||
|
.reg_stride = 4,
|
||||||
|
.max_register = 0x88,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dspi_probe(struct platform_device *pdev)
|
static int dspi_probe(struct platform_device *pdev)
|
||||||
|
@ -440,6 +451,7 @@ static int dspi_probe(struct platform_device *pdev)
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct fsl_dspi *dspi;
|
struct fsl_dspi *dspi;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
void __iomem *base;
|
||||||
int ret = 0, cs_num, bus_num;
|
int ret = 0, cs_num, bus_num;
|
||||||
|
|
||||||
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
|
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
|
||||||
|
@ -474,12 +486,24 @@ static int dspi_probe(struct platform_device *pdev)
|
||||||
master->bus_num = bus_num;
|
master->bus_num = bus_num;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
dspi->base = devm_ioremap_resource(&pdev->dev, res);
|
base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(dspi->base)) {
|
if (IS_ERR(base)) {
|
||||||
ret = PTR_ERR(dspi->base);
|
ret = PTR_ERR(base);
|
||||||
goto out_master_put;
|
goto out_master_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dspi_regmap_config.lock_arg = dspi;
|
||||||
|
dspi_regmap_config.val_format_endian =
|
||||||
|
of_property_read_bool(np, "big-endian")
|
||||||
|
? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT;
|
||||||
|
dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
|
||||||
|
&dspi_regmap_config);
|
||||||
|
if (IS_ERR(dspi->regmap)) {
|
||||||
|
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
|
||||||
|
PTR_ERR(dspi->regmap));
|
||||||
|
return PTR_ERR(dspi->regmap);
|
||||||
|
}
|
||||||
|
|
||||||
dspi->irq = platform_get_irq(pdev, 0);
|
dspi->irq = platform_get_irq(pdev, 0);
|
||||||
if (dspi->irq < 0) {
|
if (dspi->irq < 0) {
|
||||||
dev_err(&pdev->dev, "can't get platform irq\n");
|
dev_err(&pdev->dev, "can't get platform irq\n");
|
||||||
|
|
|
@ -219,13 +219,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||||
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
|
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
|
||||||
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
|
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
|
||||||
unsigned int len = t->len;
|
unsigned int len = t->len;
|
||||||
u8 bits_per_word;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
bits_per_word = spi->bits_per_word;
|
|
||||||
if (t->bits_per_word)
|
|
||||||
bits_per_word = t->bits_per_word;
|
|
||||||
|
|
||||||
mpc8xxx_spi->len = t->len;
|
mpc8xxx_spi->len = t->len;
|
||||||
len = roundup(len, 4) / 4;
|
len = roundup(len, 4) / 4;
|
||||||
|
|
||||||
|
|
|
@ -200,7 +200,7 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
|
||||||
const void *prop;
|
const void *prop;
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
|
pinfo = devm_kzalloc(&ofdev->dev, sizeof(*pinfo), GFP_KERNEL);
|
||||||
if (!pinfo)
|
if (!pinfo)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -215,15 +215,13 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
|
||||||
pdata->sysclk = get_brgfreq();
|
pdata->sysclk = get_brgfreq();
|
||||||
if (pdata->sysclk == -1) {
|
if (pdata->sysclk == -1) {
|
||||||
pdata->sysclk = fsl_get_sys_freq();
|
pdata->sysclk = fsl_get_sys_freq();
|
||||||
if (pdata->sysclk == -1) {
|
if (pdata->sysclk == -1)
|
||||||
ret = -ENODEV;
|
return -ENODEV;
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk);
|
ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
return ret;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
prop = of_get_property(np, "mode", NULL);
|
prop = of_get_property(np, "mode", NULL);
|
||||||
|
@ -237,8 +235,4 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
|
||||||
pdata->flags = SPI_CPM_MODE | SPI_CPM1;
|
pdata->flags = SPI_CPM_MODE | SPI_CPM1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err:
|
|
||||||
kfree(pinfo);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,12 +239,6 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
|
||||||
if (!bits_per_word)
|
if (!bits_per_word)
|
||||||
bits_per_word = spi->bits_per_word;
|
bits_per_word = spi->bits_per_word;
|
||||||
|
|
||||||
/* Make sure its a bit width we support [4..16, 32] */
|
|
||||||
if ((bits_per_word < 4)
|
|
||||||
|| ((bits_per_word > 16) && (bits_per_word != 32))
|
|
||||||
|| (bits_per_word > mpc8xxx_spi->max_bits_per_word))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!hz)
|
if (!hz)
|
||||||
hz = spi->max_speed_hz;
|
hz = spi->max_speed_hz;
|
||||||
|
|
||||||
|
@ -362,18 +356,28 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
|
||||||
static void fsl_spi_do_one_msg(struct spi_message *m)
|
static void fsl_spi_do_one_msg(struct spi_message *m)
|
||||||
{
|
{
|
||||||
struct spi_device *spi = m->spi;
|
struct spi_device *spi = m->spi;
|
||||||
struct spi_transfer *t;
|
struct spi_transfer *t, *first;
|
||||||
unsigned int cs_change;
|
unsigned int cs_change;
|
||||||
const int nsecs = 50;
|
const int nsecs = 50;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
/* Don't allow changes if CS is active */
|
||||||
|
first = list_first_entry(&m->transfers, struct spi_transfer,
|
||||||
|
transfer_list);
|
||||||
|
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||||
|
if ((first->bits_per_word != t->bits_per_word) ||
|
||||||
|
(first->speed_hz != t->speed_hz)) {
|
||||||
|
status = -EINVAL;
|
||||||
|
dev_err(&spi->dev,
|
||||||
|
"bits_per_word/speed_hz should be same for the same SPI transfer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cs_change = 1;
|
cs_change = 1;
|
||||||
status = 0;
|
status = -EINVAL;
|
||||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||||
if (t->bits_per_word || t->speed_hz) {
|
if (t->bits_per_word || t->speed_hz) {
|
||||||
/* Don't allow changes if CS is active */
|
|
||||||
status = -EINVAL;
|
|
||||||
|
|
||||||
if (cs_change)
|
if (cs_change)
|
||||||
status = fsl_spi_setup_transfer(spi, t);
|
status = fsl_spi_setup_transfer(spi, t);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
|
@ -641,6 +645,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
|
||||||
if (mpc8xxx_spi->type == TYPE_GRLIB)
|
if (mpc8xxx_spi->type == TYPE_GRLIB)
|
||||||
fsl_spi_grlib_probe(dev);
|
fsl_spi_grlib_probe(dev);
|
||||||
|
|
||||||
|
master->bits_per_word_mask =
|
||||||
|
(SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) &
|
||||||
|
SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word);
|
||||||
|
|
||||||
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
|
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
|
||||||
mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts;
|
mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts;
|
||||||
|
|
||||||
|
|
|
@ -250,7 +250,7 @@ static int spi_gpio_setup(struct spi_device *spi)
|
||||||
/*
|
/*
|
||||||
* ... otherwise, take it from spi->controller_data
|
* ... otherwise, take it from spi->controller_data
|
||||||
*/
|
*/
|
||||||
cs = (unsigned int) spi->controller_data;
|
cs = (unsigned int)(uintptr_t) spi->controller_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!spi->controller_state) {
|
if (!spi->controller_state) {
|
||||||
|
|
|
@ -459,9 +459,8 @@ static void giveback(struct pl022 *pl022)
|
||||||
struct spi_transfer *last_transfer;
|
struct spi_transfer *last_transfer;
|
||||||
pl022->next_msg_cs_active = false;
|
pl022->next_msg_cs_active = false;
|
||||||
|
|
||||||
last_transfer = list_entry(pl022->cur_msg->transfers.prev,
|
last_transfer = list_last_entry(&pl022->cur_msg->transfers,
|
||||||
struct spi_transfer,
|
struct spi_transfer, transfer_list);
|
||||||
transfer_list);
|
|
||||||
|
|
||||||
/* Delay if requested before any change in chip select */
|
/* Delay if requested before any change in chip select */
|
||||||
if (last_transfer->delay_usecs)
|
if (last_transfer->delay_usecs)
|
||||||
|
|
|
@ -362,8 +362,7 @@ static void giveback(struct driver_data *drv_data)
|
||||||
drv_data->cur_msg = NULL;
|
drv_data->cur_msg = NULL;
|
||||||
drv_data->cur_transfer = NULL;
|
drv_data->cur_transfer = NULL;
|
||||||
|
|
||||||
last_transfer = list_entry(msg->transfers.prev,
|
last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
|
||||||
struct spi_transfer,
|
|
||||||
transfer_list);
|
transfer_list);
|
||||||
|
|
||||||
/* Delay if requested before any change in chip select */
|
/* Delay if requested before any change in chip select */
|
||||||
|
|
Loading…
Add table
Reference in a new issue