You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge remote-tracking branches 'spi/topic/dw', 'spi/topic/fsl', 'spi/topic/fsl-espi' and 'spi/topic/id-const' into spi-next
This commit is contained in:
@@ -42,6 +42,10 @@ Required properties:
|
|||||||
- interrupts : should contain eSPI interrupt, the device has one interrupt.
|
- interrupts : should contain eSPI interrupt, the device has one interrupt.
|
||||||
- fsl,espi-num-chipselects : the number of the chipselect signals.
|
- fsl,espi-num-chipselects : the number of the chipselect signals.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- fsl,csbef: chip select assertion time in bits before frame starts
|
||||||
|
- fsl,csaft: chip select negation time in bits after frame ends
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
spi@110000 {
|
spi@110000 {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
@@ -51,4 +55,6 @@ Example:
|
|||||||
interrupts = <53 0x2>;
|
interrupts = <53 0x2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
fsl,espi-num-chipselects = <4>;
|
fsl,espi-num-chipselects = <4>;
|
||||||
|
fsl,csbef = <1>;
|
||||||
|
fsl,csaft = <1>;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
Synopsys DesignWare SPI master
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be "snps,designware-spi"
|
||||||
|
- #address-cells: see spi-bus.txt
|
||||||
|
- #size-cells: see spi-bus.txt
|
||||||
|
- reg: address and length of the spi master registers
|
||||||
|
- interrupts: should contain one interrupt
|
||||||
|
- clocks: spi clock phandle
|
||||||
|
- num-cs: see spi-bus.txt
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- cs-gpios: see spi-bus.txt
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
spi: spi@4020a000 {
|
||||||
|
compatible = "snps,designware-spi";
|
||||||
|
interrupts = <11 1>;
|
||||||
|
reg = <0x4020a000 0x1000>;
|
||||||
|
clocks = <&pclk>;
|
||||||
|
num-cs = <2>;
|
||||||
|
cs-gpios = <&banka 0 0>;
|
||||||
|
};
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/of_gpio.h>
|
||||||
|
|
||||||
#include "spi-dw.h"
|
#include "spi-dw.h"
|
||||||
|
|
||||||
@@ -70,6 +71,27 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
|
|||||||
dws->num_cs = 4;
|
dws->num_cs = 4;
|
||||||
dws->max_freq = clk_get_rate(dwsmmio->clk);
|
dws->max_freq = clk_get_rate(dwsmmio->clk);
|
||||||
|
|
||||||
|
if (pdev->dev.of_node) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < dws->num_cs; i++) {
|
||||||
|
int cs_gpio = of_get_named_gpio(pdev->dev.of_node,
|
||||||
|
"cs-gpios", i);
|
||||||
|
|
||||||
|
if (cs_gpio == -EPROBE_DEFER) {
|
||||||
|
ret = cs_gpio;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpio_is_valid(cs_gpio)) {
|
||||||
|
ret = devm_gpio_request(&pdev->dev, cs_gpio,
|
||||||
|
dev_name(&pdev->dev));
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ret = dw_spi_add_host(&pdev->dev, dws);
|
ret = dw_spi_add_host(&pdev->dev, dws);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
+22
-175
@@ -24,6 +24,7 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
|
||||||
#include "spi-dw.h"
|
#include "spi-dw.h"
|
||||||
|
|
||||||
@@ -36,12 +37,6 @@
|
|||||||
#define DONE_STATE ((void *)2)
|
#define DONE_STATE ((void *)2)
|
||||||
#define ERROR_STATE ((void *)-1)
|
#define ERROR_STATE ((void *)-1)
|
||||||
|
|
||||||
#define QUEUE_RUNNING 0
|
|
||||||
#define QUEUE_STOPPED 1
|
|
||||||
|
|
||||||
#define MRST_SPI_DEASSERT 0
|
|
||||||
#define MRST_SPI_ASSERT 1
|
|
||||||
|
|
||||||
/* Slave spi_dev related */
|
/* Slave spi_dev related */
|
||||||
struct chip_data {
|
struct chip_data {
|
||||||
u16 cr0;
|
u16 cr0;
|
||||||
@@ -263,28 +258,22 @@ static int map_dma_buffers(struct dw_spi *dws)
|
|||||||
static void giveback(struct dw_spi *dws)
|
static void giveback(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
struct spi_transfer *last_transfer;
|
struct spi_transfer *last_transfer;
|
||||||
unsigned long flags;
|
|
||||||
struct spi_message *msg;
|
struct spi_message *msg;
|
||||||
|
|
||||||
spin_lock_irqsave(&dws->lock, flags);
|
|
||||||
msg = dws->cur_msg;
|
msg = dws->cur_msg;
|
||||||
dws->cur_msg = NULL;
|
dws->cur_msg = NULL;
|
||||||
dws->cur_transfer = NULL;
|
dws->cur_transfer = NULL;
|
||||||
dws->prev_chip = dws->cur_chip;
|
dws->prev_chip = dws->cur_chip;
|
||||||
dws->cur_chip = NULL;
|
dws->cur_chip = NULL;
|
||||||
dws->dma_mapped = 0;
|
dws->dma_mapped = 0;
|
||||||
queue_work(dws->workqueue, &dws->pump_messages);
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
|
|
||||||
last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
|
last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
|
||||||
transfer_list);
|
transfer_list);
|
||||||
|
|
||||||
if (!last_transfer->cs_change && dws->cs_control)
|
if (!last_transfer->cs_change)
|
||||||
dws->cs_control(MRST_SPI_DEASSERT);
|
spi_chip_sel(dws, dws->cur_msg->spi, 0);
|
||||||
|
|
||||||
msg->state = NULL;
|
spi_finalize_current_message(dws->master);
|
||||||
if (msg->complete)
|
|
||||||
msg->complete(msg->context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void int_error_stop(struct dw_spi *dws, const char *msg)
|
static void int_error_stop(struct dw_spi *dws, const char *msg)
|
||||||
@@ -502,7 +491,7 @@ static void pump_transfers(unsigned long data)
|
|||||||
dw_writew(dws, DW_SPI_CTRL0, cr0);
|
dw_writew(dws, DW_SPI_CTRL0, cr0);
|
||||||
|
|
||||||
spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
|
spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
|
||||||
spi_chip_sel(dws, spi->chip_select);
|
spi_chip_sel(dws, spi, 1);
|
||||||
|
|
||||||
/* Set the interrupt mask, for poll mode just disable all int */
|
/* Set the interrupt mask, for poll mode just disable all int */
|
||||||
spi_mask_intr(dws, 0xff);
|
spi_mask_intr(dws, 0xff);
|
||||||
@@ -529,30 +518,12 @@ early_exit:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pump_messages(struct work_struct *work)
|
static int dw_spi_transfer_one_message(struct spi_master *master,
|
||||||
|
struct spi_message *msg)
|
||||||
{
|
{
|
||||||
struct dw_spi *dws =
|
struct dw_spi *dws = spi_master_get_devdata(master);
|
||||||
container_of(work, struct dw_spi, pump_messages);
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
/* Lock queue and check for queue work */
|
|
||||||
spin_lock_irqsave(&dws->lock, flags);
|
|
||||||
if (list_empty(&dws->queue) || dws->run == QUEUE_STOPPED) {
|
|
||||||
dws->busy = 0;
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure we are not already running a message */
|
|
||||||
if (dws->cur_msg) {
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extract head of queue */
|
|
||||||
dws->cur_msg = list_entry(dws->queue.next, struct spi_message, queue);
|
|
||||||
list_del_init(&dws->cur_msg->queue);
|
|
||||||
|
|
||||||
|
dws->cur_msg = msg;
|
||||||
/* Initial message state*/
|
/* Initial message state*/
|
||||||
dws->cur_msg->state = START_STATE;
|
dws->cur_msg->state = START_STATE;
|
||||||
dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
|
dws->cur_transfer = list_entry(dws->cur_msg->transfers.next,
|
||||||
@@ -560,46 +531,9 @@ static void pump_messages(struct work_struct *work)
|
|||||||
transfer_list);
|
transfer_list);
|
||||||
dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);
|
dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi);
|
||||||
|
|
||||||
/* Mark as busy and launch transfers */
|
/* Launch transfers */
|
||||||
tasklet_schedule(&dws->pump_transfers);
|
tasklet_schedule(&dws->pump_transfers);
|
||||||
|
|
||||||
dws->busy = 1;
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* spi_device use this to queue in their spi_msg */
|
|
||||||
static int dw_spi_transfer(struct spi_device *spi, struct spi_message *msg)
|
|
||||||
{
|
|
||||||
struct dw_spi *dws = spi_master_get_devdata(spi->master);
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dws->lock, flags);
|
|
||||||
|
|
||||||
if (dws->run == QUEUE_STOPPED) {
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
return -ESHUTDOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg->actual_length = 0;
|
|
||||||
msg->status = -EINPROGRESS;
|
|
||||||
msg->state = START_STATE;
|
|
||||||
|
|
||||||
list_add_tail(&msg->queue, &dws->queue);
|
|
||||||
|
|
||||||
if (dws->run == QUEUE_RUNNING && !dws->busy) {
|
|
||||||
|
|
||||||
if (dws->cur_transfer || dws->cur_msg)
|
|
||||||
queue_work(dws->workqueue,
|
|
||||||
&dws->pump_messages);
|
|
||||||
else {
|
|
||||||
/* If no other data transaction in air, just go */
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
pump_messages(&dws->pump_messages);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,6 +542,7 @@ static int dw_spi_setup(struct spi_device *spi)
|
|||||||
{
|
{
|
||||||
struct dw_spi_chip *chip_info = NULL;
|
struct dw_spi_chip *chip_info = NULL;
|
||||||
struct chip_data *chip;
|
struct chip_data *chip;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Only alloc on first setup */
|
/* Only alloc on first setup */
|
||||||
chip = spi_get_ctldata(spi);
|
chip = spi_get_ctldata(spi);
|
||||||
@@ -661,81 +596,13 @@ static int dw_spi_setup(struct spi_device *spi)
|
|||||||
| (spi->mode << SPI_MODE_OFFSET)
|
| (spi->mode << SPI_MODE_OFFSET)
|
||||||
| (chip->tmode << SPI_TMOD_OFFSET);
|
| (chip->tmode << SPI_TMOD_OFFSET);
|
||||||
|
|
||||||
return 0;
|
if (gpio_is_valid(spi->cs_gpio)) {
|
||||||
}
|
ret = gpio_direction_output(spi->cs_gpio,
|
||||||
|
!(spi->mode & SPI_CS_HIGH));
|
||||||
static int init_queue(struct dw_spi *dws)
|
if (ret)
|
||||||
{
|
return ret;
|
||||||
INIT_LIST_HEAD(&dws->queue);
|
|
||||||
spin_lock_init(&dws->lock);
|
|
||||||
|
|
||||||
dws->run = QUEUE_STOPPED;
|
|
||||||
dws->busy = 0;
|
|
||||||
|
|
||||||
tasklet_init(&dws->pump_transfers,
|
|
||||||
pump_transfers, (unsigned long)dws);
|
|
||||||
|
|
||||||
INIT_WORK(&dws->pump_messages, pump_messages);
|
|
||||||
dws->workqueue = create_singlethread_workqueue(
|
|
||||||
dev_name(dws->master->dev.parent));
|
|
||||||
if (dws->workqueue == NULL)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int start_queue(struct dw_spi *dws)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dws->lock, flags);
|
|
||||||
|
|
||||||
if (dws->run == QUEUE_RUNNING || dws->busy) {
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dws->run = QUEUE_RUNNING;
|
|
||||||
dws->cur_msg = NULL;
|
|
||||||
dws->cur_transfer = NULL;
|
|
||||||
dws->cur_chip = NULL;
|
|
||||||
dws->prev_chip = NULL;
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
|
|
||||||
queue_work(dws->workqueue, &dws->pump_messages);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stop_queue(struct dw_spi *dws)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
unsigned limit = 50;
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&dws->lock, flags);
|
|
||||||
dws->run = QUEUE_STOPPED;
|
|
||||||
while ((!list_empty(&dws->queue) || dws->busy) && limit--) {
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
msleep(10);
|
|
||||||
spin_lock_irqsave(&dws->lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!list_empty(&dws->queue) || dws->busy)
|
|
||||||
status = -EBUSY;
|
|
||||||
spin_unlock_irqrestore(&dws->lock, flags);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int destroy_queue(struct dw_spi *dws)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
|
|
||||||
status = stop_queue(dws);
|
|
||||||
if (status != 0)
|
|
||||||
return status;
|
|
||||||
destroy_workqueue(dws->workqueue);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -794,7 +661,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
|||||||
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->setup = dw_spi_setup;
|
master->setup = dw_spi_setup;
|
||||||
master->transfer = dw_spi_transfer;
|
master->transfer_one_message = dw_spi_transfer_one_message;
|
||||||
master->max_speed_hz = dws->max_freq;
|
master->max_speed_hz = dws->max_freq;
|
||||||
|
|
||||||
/* Basic HW init */
|
/* Basic HW init */
|
||||||
@@ -808,33 +675,21 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initial and start queue */
|
tasklet_init(&dws->pump_transfers, pump_transfers, (unsigned long)dws);
|
||||||
ret = init_queue(dws);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&master->dev, "problem initializing queue\n");
|
|
||||||
goto err_diable_hw;
|
|
||||||
}
|
|
||||||
ret = start_queue(dws);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&master->dev, "problem starting queue\n");
|
|
||||||
goto err_diable_hw;
|
|
||||||
}
|
|
||||||
|
|
||||||
spi_master_set_devdata(master, dws);
|
spi_master_set_devdata(master, dws);
|
||||||
ret = devm_spi_register_master(dev, master);
|
ret = devm_spi_register_master(dev, master);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&master->dev, "problem registering spi master\n");
|
dev_err(&master->dev, "problem registering spi master\n");
|
||||||
goto err_queue_alloc;
|
goto err_dma_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
mrst_spi_debugfs_init(dws);
|
mrst_spi_debugfs_init(dws);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_queue_alloc:
|
err_dma_exit:
|
||||||
destroy_queue(dws);
|
|
||||||
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
||||||
dws->dma_ops->dma_exit(dws);
|
dws->dma_ops->dma_exit(dws);
|
||||||
err_diable_hw:
|
|
||||||
spi_enable_chip(dws, 0);
|
spi_enable_chip(dws, 0);
|
||||||
err_free_master:
|
err_free_master:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
@@ -844,18 +699,10 @@ EXPORT_SYMBOL_GPL(dw_spi_add_host);
|
|||||||
|
|
||||||
void dw_spi_remove_host(struct dw_spi *dws)
|
void dw_spi_remove_host(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
if (!dws)
|
if (!dws)
|
||||||
return;
|
return;
|
||||||
mrst_spi_debugfs_remove(dws);
|
mrst_spi_debugfs_remove(dws);
|
||||||
|
|
||||||
/* Remove the queue */
|
|
||||||
status = destroy_queue(dws);
|
|
||||||
if (status != 0)
|
|
||||||
dev_err(&dws->master->dev,
|
|
||||||
"dw_spi_remove: workqueue will not complete, message memory not freed\n");
|
|
||||||
|
|
||||||
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
if (dws->dma_ops && dws->dma_ops->dma_exit)
|
||||||
dws->dma_ops->dma_exit(dws);
|
dws->dma_ops->dma_exit(dws);
|
||||||
spi_enable_chip(dws, 0);
|
spi_enable_chip(dws, 0);
|
||||||
@@ -868,7 +715,7 @@ int dw_spi_suspend_host(struct dw_spi *dws)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ret = stop_queue(dws);
|
ret = spi_master_suspend(dws->master);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
spi_enable_chip(dws, 0);
|
spi_enable_chip(dws, 0);
|
||||||
@@ -882,7 +729,7 @@ int dw_spi_resume_host(struct dw_spi *dws)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
spi_hw_init(dws);
|
spi_hw_init(dws);
|
||||||
ret = start_queue(dws);
|
ret = spi_master_resume(dws->master);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
|
dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
+11
-13
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
|
||||||
/* Register offsets */
|
/* Register offsets */
|
||||||
#define DW_SPI_CTRL0 0x00
|
#define DW_SPI_CTRL0 0x00
|
||||||
@@ -104,14 +105,6 @@ struct dw_spi {
|
|||||||
u16 bus_num;
|
u16 bus_num;
|
||||||
u16 num_cs; /* supported slave numbers */
|
u16 num_cs; /* supported slave numbers */
|
||||||
|
|
||||||
/* Driver message queue */
|
|
||||||
struct workqueue_struct *workqueue;
|
|
||||||
struct work_struct pump_messages;
|
|
||||||
spinlock_t lock;
|
|
||||||
struct list_head queue;
|
|
||||||
int busy;
|
|
||||||
int run;
|
|
||||||
|
|
||||||
/* Message Transfer pump */
|
/* Message Transfer pump */
|
||||||
struct tasklet_struct pump_transfers;
|
struct tasklet_struct pump_transfers;
|
||||||
|
|
||||||
@@ -186,15 +179,20 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div)
|
|||||||
dw_writel(dws, DW_SPI_BAUDR, div);
|
dw_writel(dws, DW_SPI_BAUDR, div);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void spi_chip_sel(struct dw_spi *dws, u16 cs)
|
static inline void spi_chip_sel(struct dw_spi *dws, struct spi_device *spi,
|
||||||
|
int active)
|
||||||
{
|
{
|
||||||
if (cs > dws->num_cs)
|
u16 cs = spi->chip_select;
|
||||||
return;
|
int gpio_val = active ? (spi->mode & SPI_CS_HIGH) :
|
||||||
|
!(spi->mode & SPI_CS_HIGH);
|
||||||
|
|
||||||
if (dws->cs_control)
|
if (dws->cs_control)
|
||||||
dws->cs_control(1);
|
dws->cs_control(active);
|
||||||
|
if (gpio_is_valid(spi->cs_gpio))
|
||||||
|
gpio_set_value(spi->cs_gpio, gpio_val);
|
||||||
|
|
||||||
dw_writel(dws, DW_SPI_SER, 1 << cs);
|
if (active)
|
||||||
|
dw_writel(dws, DW_SPI_SER, 1 << cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable IRQ bits */
|
/* Disable IRQ bits */
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct of_device_id fsl_dspi_dt_ids[] = {
|
static const struct of_device_id fsl_dspi_dt_ids[] = {
|
||||||
{ .compatible = "fsl,vf610-dspi", .data = NULL, },
|
{ .compatible = "fsl,vf610-dspi", .data = NULL, },
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -348,7 +348,7 @@ static void fsl_espi_cmd_trans(struct spi_message *m,
|
|||||||
}
|
}
|
||||||
|
|
||||||
espi_trans->tx_buf = local_buf;
|
espi_trans->tx_buf = local_buf;
|
||||||
espi_trans->rx_buf = local_buf + espi_trans->n_tx;
|
espi_trans->rx_buf = local_buf;
|
||||||
fsl_espi_do_trans(m, espi_trans);
|
fsl_espi_do_trans(m, espi_trans);
|
||||||
|
|
||||||
espi_trans->actual_length = espi_trans->len;
|
espi_trans->actual_length = espi_trans->len;
|
||||||
@@ -397,7 +397,7 @@ static void fsl_espi_rw_trans(struct spi_message *m,
|
|||||||
espi_trans->n_rx = trans_len;
|
espi_trans->n_rx = trans_len;
|
||||||
espi_trans->len = trans_len + n_tx;
|
espi_trans->len = trans_len + n_tx;
|
||||||
espi_trans->tx_buf = local_buf;
|
espi_trans->tx_buf = local_buf;
|
||||||
espi_trans->rx_buf = local_buf + n_tx;
|
espi_trans->rx_buf = local_buf;
|
||||||
fsl_espi_do_trans(m, espi_trans);
|
fsl_espi_do_trans(m, espi_trans);
|
||||||
|
|
||||||
memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len);
|
memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len);
|
||||||
@@ -458,7 +458,7 @@ static int fsl_espi_setup(struct spi_device *spi)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!cs) {
|
if (!cs) {
|
||||||
cs = kzalloc(sizeof *cs, GFP_KERNEL);
|
cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL);
|
||||||
if (!cs)
|
if (!cs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
spi->controller_state = cs;
|
spi->controller_state = cs;
|
||||||
@@ -586,8 +586,10 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
|
|||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct mpc8xxx_spi *mpc8xxx_spi;
|
struct mpc8xxx_spi *mpc8xxx_spi;
|
||||||
struct fsl_espi_reg *reg_base;
|
struct fsl_espi_reg *reg_base;
|
||||||
u32 regval;
|
struct device_node *nc;
|
||||||
int i, ret = 0;
|
const __be32 *prop;
|
||||||
|
u32 regval, csmode;
|
||||||
|
int i, len, ret = 0;
|
||||||
|
|
||||||
master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
|
master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
|
||||||
if (!master) {
|
if (!master) {
|
||||||
@@ -634,8 +636,32 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
|
|||||||
mpc8xxx_spi_write_reg(®_base->event, 0xffffffff);
|
mpc8xxx_spi_write_reg(®_base->event, 0xffffffff);
|
||||||
|
|
||||||
/* Init eSPI CS mode register */
|
/* Init eSPI CS mode register */
|
||||||
for (i = 0; i < pdata->max_chipselect; i++)
|
for_each_available_child_of_node(master->dev.of_node, nc) {
|
||||||
mpc8xxx_spi_write_reg(®_base->csmode[i], CSMODE_INIT_VAL);
|
/* get chip select */
|
||||||
|
prop = of_get_property(nc, "reg", &len);
|
||||||
|
if (!prop || len < sizeof(*prop))
|
||||||
|
continue;
|
||||||
|
i = be32_to_cpup(prop);
|
||||||
|
if (i < 0 || i >= pdata->max_chipselect)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
csmode = CSMODE_INIT_VAL;
|
||||||
|
/* check if CSBEF is set in device tree */
|
||||||
|
prop = of_get_property(nc, "fsl,csbef", &len);
|
||||||
|
if (prop && len >= sizeof(*prop)) {
|
||||||
|
csmode &= ~(CSMODE_BEF(0xf));
|
||||||
|
csmode |= CSMODE_BEF(be32_to_cpup(prop));
|
||||||
|
}
|
||||||
|
/* check if CSAFT is set in device tree */
|
||||||
|
prop = of_get_property(nc, "fsl,csaft", &len);
|
||||||
|
if (prop && len >= sizeof(*prop)) {
|
||||||
|
csmode &= ~(CSMODE_AFT(0xf));
|
||||||
|
csmode |= CSMODE_AFT(be32_to_cpup(prop));
|
||||||
|
}
|
||||||
|
mpc8xxx_spi_write_reg(®_base->csmode[i], csmode);
|
||||||
|
|
||||||
|
dev_info(dev, "cs=%d, init_csmode=0x%x\n", i, csmode);
|
||||||
|
}
|
||||||
|
|
||||||
/* Enable SPI interface */
|
/* Enable SPI interface */
|
||||||
regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
|
regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
|
||||||
|
|||||||
@@ -99,11 +99,6 @@ int mpc8xxx_spi_transfer(struct spi_device *spi,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mpc8xxx_spi_cleanup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
kfree(spi->controller_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *mpc8xxx_spi_strmode(unsigned int flags)
|
const char *mpc8xxx_spi_strmode(unsigned int flags)
|
||||||
{
|
{
|
||||||
if (flags & SPI_QE_CPU_MODE) {
|
if (flags & SPI_QE_CPU_MODE) {
|
||||||
@@ -134,7 +129,6 @@ int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
|
|||||||
| SPI_LSB_FIRST | SPI_LOOP;
|
| SPI_LSB_FIRST | SPI_LOOP;
|
||||||
|
|
||||||
master->transfer = mpc8xxx_spi_transfer;
|
master->transfer = mpc8xxx_spi_transfer;
|
||||||
master->cleanup = mpc8xxx_spi_cleanup;
|
|
||||||
master->dev.of_node = dev->of_node;
|
master->dev.of_node = dev->of_node;
|
||||||
|
|
||||||
mpc8xxx_spi = spi_master_get_devdata(master);
|
mpc8xxx_spi = spi_master_get_devdata(master);
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ extern struct mpc8xxx_spi_probe_info *to_of_pinfo(
|
|||||||
extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
|
extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
|
||||||
struct spi_transfer *t, unsigned int len);
|
struct spi_transfer *t, unsigned int len);
|
||||||
extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m);
|
extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m);
|
||||||
extern void mpc8xxx_spi_cleanup(struct spi_device *spi);
|
|
||||||
extern const char *mpc8xxx_spi_strmode(unsigned int flags);
|
extern const char *mpc8xxx_spi_strmode(unsigned int flags);
|
||||||
extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
|
extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
|
||||||
unsigned int irq);
|
unsigned int irq);
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ static int fsl_spi_setup(struct spi_device *spi)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!cs) {
|
if (!cs) {
|
||||||
cs = kzalloc(sizeof *cs, GFP_KERNEL);
|
cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL);
|
||||||
if (!cs)
|
if (!cs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
spi->controller_state = cs;
|
spi->controller_state = cs;
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
static struct of_device_id spi_gpio_dt_ids[] = {
|
static const struct of_device_id spi_gpio_dt_ids[] = {
|
||||||
{ .compatible = "spi-gpio" },
|
{ .compatible = "spi-gpio" },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -749,7 +749,7 @@ static int spi_qup_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct of_device_id spi_qup_dt_match[] = {
|
static const struct of_device_id spi_qup_dt_match[] = {
|
||||||
{ .compatible = "qcom,spi-qup-v2.1.1", },
|
{ .compatible = "qcom,spi-qup-v2.1.1", },
|
||||||
{ .compatible = "qcom,spi-qup-v2.2.1", },
|
{ .compatible = "qcom,spi-qup-v2.2.1", },
|
||||||
{ }
|
{ }
|
||||||
|
|||||||
@@ -1012,7 +1012,7 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
|
|||||||
return IRQ_WAKE_THREAD;
|
return IRQ_WAKE_THREAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct of_device_id tegra_spi_of_match[] = {
|
static const struct of_device_id tegra_spi_of_match[] = {
|
||||||
{ .compatible = "nvidia,tegra114-spi", },
|
{ .compatible = "nvidia,tegra114-spi", },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data)
|
|||||||
return handle_cpu_based_xfer(tsd);
|
return handle_cpu_based_xfer(tsd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct of_device_id tegra_sflash_of_match[] = {
|
static const struct of_device_id tegra_sflash_of_match[] = {
|
||||||
{ .compatible = "nvidia,tegra20-sflash", },
|
{ .compatible = "nvidia,tegra20-sflash", },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1001,7 +1001,7 @@ static const struct tegra_slink_chip_data tegra20_spi_cdata = {
|
|||||||
.cs_hold_time = false,
|
.cs_hold_time = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct of_device_id tegra_slink_of_match[] = {
|
static const struct of_device_id tegra_slink_of_match[] = {
|
||||||
{ .compatible = "nvidia,tegra30-slink", .data = &tegra30_spi_cdata, },
|
{ .compatible = "nvidia,tegra30-slink", .data = &tegra30_spi_cdata, },
|
||||||
{ .compatible = "nvidia,tegra20-slink", .data = &tegra20_spi_cdata, },
|
{ .compatible = "nvidia,tegra20-slink", .data = &tegra20_spi_cdata, },
|
||||||
{}
|
{}
|
||||||
|
|||||||
Reference in New Issue
Block a user