提交 ae24a21b 编写于 作者: L Linus Torvalds

Merge tag 'spi-fix-v5.6-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "A selection of small fixes, mostly for drivers, that have arrived
  since the merge window. None of them are earth shattering in
  themselves but all useful for affected systems"

* tag 'spi-fix-v5.6-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: spi_register_controller(): free bus id on error paths
  spi: bcm63xx-hsspi: Really keep pll clk enabled
  spi: atmel-quadspi: fix possible MMIO window size overrun
  spi/zynqmp: remove entry that causes a cs glitch
  spi: pxa2xx: Add CS control clock quirk
  spi: spidev: Fix CS polarity if GPIO descriptors are used
  spi: qup: call spi_qup_pm_resume_runtime before suspending
  spi: spi-omap2-mcspi: Support probe deferral for DMA channels
  spi: spi-omap2-mcspi: Handle DMA size restriction on AM65x
...@@ -149,6 +149,7 @@ struct atmel_qspi { ...@@ -149,6 +149,7 @@ struct atmel_qspi {
struct clk *qspick; struct clk *qspick;
struct platform_device *pdev; struct platform_device *pdev;
const struct atmel_qspi_caps *caps; const struct atmel_qspi_caps *caps;
resource_size_t mmap_size;
u32 pending; u32 pending;
u32 mr; u32 mr;
u32 scr; u32 scr;
...@@ -329,6 +330,14 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) ...@@ -329,6 +330,14 @@ static int atmel_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
u32 sr, offset; u32 sr, offset;
int err; int err;
/*
* Check if the address exceeds the MMIO window size. An improvement
* would be to add support for regular SPI mode and fall back to it
* when the flash memories overrun the controller's memory space.
*/
if (op->addr.val + op->data.nbytes > aq->mmap_size)
return -ENOTSUPP;
err = atmel_qspi_set_cfg(aq, op, &offset); err = atmel_qspi_set_cfg(aq, op, &offset);
if (err) if (err)
return err; return err;
...@@ -480,6 +489,8 @@ static int atmel_qspi_probe(struct platform_device *pdev) ...@@ -480,6 +489,8 @@ static int atmel_qspi_probe(struct platform_device *pdev)
goto exit; goto exit;
} }
aq->mmap_size = resource_size(res);
/* Get the peripheral clock */ /* Get the peripheral clock */
aq->pclk = devm_clk_get(&pdev->dev, "pclk"); aq->pclk = devm_clk_get(&pdev->dev, "pclk");
if (IS_ERR(aq->pclk)) if (IS_ERR(aq->pclk))
......
...@@ -366,7 +366,6 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) ...@@ -366,7 +366,6 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
goto out_disable_clk; goto out_disable_clk;
rate = clk_get_rate(pll_clk); rate = clk_get_rate(pll_clk);
clk_disable_unprepare(pll_clk);
if (!rate) { if (!rate) {
ret = -EINVAL; ret = -EINVAL;
goto out_disable_pll_clk; goto out_disable_pll_clk;
......
...@@ -130,6 +130,7 @@ struct omap2_mcspi { ...@@ -130,6 +130,7 @@ struct omap2_mcspi {
int fifo_depth; int fifo_depth;
bool slave_aborted; bool slave_aborted;
unsigned int pin_dir:1; unsigned int pin_dir:1;
size_t max_xfer_len;
}; };
struct omap2_mcspi_cs { struct omap2_mcspi_cs {
...@@ -974,20 +975,12 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, ...@@ -974,20 +975,12 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
* Note that we currently allow DMA only if we get a channel * Note that we currently allow DMA only if we get a channel
* for both rx and tx. Otherwise we'll do PIO for both rx and tx. * for both rx and tx. Otherwise we'll do PIO for both rx and tx.
*/ */
static int omap2_mcspi_request_dma(struct spi_device *spi) static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi,
struct omap2_mcspi_dma *mcspi_dma)
{ {
struct spi_master *master = spi->master;
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
int ret = 0; int ret = 0;
mcspi = spi_master_get_devdata(master); mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,
mcspi_dma = mcspi->dma_channels + spi->chip_select;
init_completion(&mcspi_dma->dma_rx_completion);
init_completion(&mcspi_dma->dma_tx_completion);
mcspi_dma->dma_rx = dma_request_chan(&master->dev,
mcspi_dma->dma_rx_ch_name); mcspi_dma->dma_rx_ch_name);
if (IS_ERR(mcspi_dma->dma_rx)) { if (IS_ERR(mcspi_dma->dma_rx)) {
ret = PTR_ERR(mcspi_dma->dma_rx); ret = PTR_ERR(mcspi_dma->dma_rx);
...@@ -995,7 +988,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi) ...@@ -995,7 +988,7 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
goto no_dma; goto no_dma;
} }
mcspi_dma->dma_tx = dma_request_chan(&master->dev, mcspi_dma->dma_tx = dma_request_chan(mcspi->dev,
mcspi_dma->dma_tx_ch_name); mcspi_dma->dma_tx_ch_name);
if (IS_ERR(mcspi_dma->dma_tx)) { if (IS_ERR(mcspi_dma->dma_tx)) {
ret = PTR_ERR(mcspi_dma->dma_tx); ret = PTR_ERR(mcspi_dma->dma_tx);
...@@ -1004,20 +997,40 @@ static int omap2_mcspi_request_dma(struct spi_device *spi) ...@@ -1004,20 +997,40 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
mcspi_dma->dma_rx = NULL; mcspi_dma->dma_rx = NULL;
} }
init_completion(&mcspi_dma->dma_rx_completion);
init_completion(&mcspi_dma->dma_tx_completion);
no_dma: no_dma:
return ret; return ret;
} }
static void omap2_mcspi_release_dma(struct spi_master *master)
{
struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
struct omap2_mcspi_dma *mcspi_dma;
int i;
for (i = 0; i < master->num_chipselect; i++) {
mcspi_dma = &mcspi->dma_channels[i];
if (mcspi_dma->dma_rx) {
dma_release_channel(mcspi_dma->dma_rx);
mcspi_dma->dma_rx = NULL;
}
if (mcspi_dma->dma_tx) {
dma_release_channel(mcspi_dma->dma_tx);
mcspi_dma->dma_tx = NULL;
}
}
}
static int omap2_mcspi_setup(struct spi_device *spi) static int omap2_mcspi_setup(struct spi_device *spi)
{ {
int ret; int ret;
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
struct omap2_mcspi_regs *ctx = &mcspi->ctx; struct omap2_mcspi_regs *ctx = &mcspi->ctx;
struct omap2_mcspi_dma *mcspi_dma;
struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi_cs *cs = spi->controller_state;
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
if (!cs) { if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL); cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs) if (!cs)
...@@ -1042,13 +1055,6 @@ static int omap2_mcspi_setup(struct spi_device *spi) ...@@ -1042,13 +1055,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
} }
} }
if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
ret = omap2_mcspi_request_dma(spi);
if (ret)
dev_warn(&spi->dev, "not using DMA for McSPI (%d)\n",
ret);
}
ret = pm_runtime_get_sync(mcspi->dev); ret = pm_runtime_get_sync(mcspi->dev);
if (ret < 0) { if (ret < 0) {
pm_runtime_put_noidle(mcspi->dev); pm_runtime_put_noidle(mcspi->dev);
...@@ -1065,12 +1071,8 @@ static int omap2_mcspi_setup(struct spi_device *spi) ...@@ -1065,12 +1071,8 @@ static int omap2_mcspi_setup(struct spi_device *spi)
static void omap2_mcspi_cleanup(struct spi_device *spi) static void omap2_mcspi_cleanup(struct spi_device *spi)
{ {
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
struct omap2_mcspi_cs *cs; struct omap2_mcspi_cs *cs;
mcspi = spi_master_get_devdata(spi->master);
if (spi->controller_state) { if (spi->controller_state) {
/* Unlink controller state from context save list */ /* Unlink controller state from context save list */
cs = spi->controller_state; cs = spi->controller_state;
...@@ -1079,19 +1081,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) ...@@ -1079,19 +1081,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
kfree(cs); kfree(cs);
} }
if (spi->chip_select < spi->master->num_chipselect) {
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
if (mcspi_dma->dma_rx) {
dma_release_channel(mcspi_dma->dma_rx);
mcspi_dma->dma_rx = NULL;
}
if (mcspi_dma->dma_tx) {
dma_release_channel(mcspi_dma->dma_tx);
mcspi_dma->dma_tx = NULL;
}
}
if (gpio_is_valid(spi->cs_gpio)) if (gpio_is_valid(spi->cs_gpio))
gpio_free(spi->cs_gpio); gpio_free(spi->cs_gpio);
} }
...@@ -1302,9 +1291,24 @@ static bool omap2_mcspi_can_dma(struct spi_master *master, ...@@ -1302,9 +1291,24 @@ static bool omap2_mcspi_can_dma(struct spi_master *master,
if (spi_controller_is_slave(master)) if (spi_controller_is_slave(master))
return true; return true;
master->dma_rx = mcspi_dma->dma_rx;
master->dma_tx = mcspi_dma->dma_tx;
return (xfer->len >= DMA_MIN_BYTES); return (xfer->len >= DMA_MIN_BYTES);
} }
static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi)
{
struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
struct omap2_mcspi_dma *mcspi_dma =
&mcspi->dma_channels[spi->chip_select];
if (mcspi->max_xfer_len && mcspi_dma->dma_rx)
return mcspi->max_xfer_len;
return SIZE_MAX;
}
static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi) static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
{ {
struct spi_master *master = mcspi->master; struct spi_master *master = mcspi->master;
...@@ -1373,6 +1377,11 @@ static struct omap2_mcspi_platform_config omap4_pdata = { ...@@ -1373,6 +1377,11 @@ static struct omap2_mcspi_platform_config omap4_pdata = {
.regs_offset = OMAP4_MCSPI_REG_OFFSET, .regs_offset = OMAP4_MCSPI_REG_OFFSET,
}; };
static struct omap2_mcspi_platform_config am654_pdata = {
.regs_offset = OMAP4_MCSPI_REG_OFFSET,
.max_xfer_len = SZ_4K - 1,
};
static const struct of_device_id omap_mcspi_of_match[] = { static const struct of_device_id omap_mcspi_of_match[] = {
{ {
.compatible = "ti,omap2-mcspi", .compatible = "ti,omap2-mcspi",
...@@ -1382,6 +1391,10 @@ static const struct of_device_id omap_mcspi_of_match[] = { ...@@ -1382,6 +1391,10 @@ static const struct of_device_id omap_mcspi_of_match[] = {
.compatible = "ti,omap4-mcspi", .compatible = "ti,omap4-mcspi",
.data = &omap4_pdata, .data = &omap4_pdata,
}, },
{
.compatible = "ti,am654-mcspi",
.data = &am654_pdata,
},
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, omap_mcspi_of_match); MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
...@@ -1439,6 +1452,10 @@ static int omap2_mcspi_probe(struct platform_device *pdev) ...@@ -1439,6 +1452,10 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
mcspi->pin_dir = pdata->pin_dir; mcspi->pin_dir = pdata->pin_dir;
} }
regs_offset = pdata->regs_offset; regs_offset = pdata->regs_offset;
if (pdata->max_xfer_len) {
mcspi->max_xfer_len = pdata->max_xfer_len;
master->max_transfer_size = omap2_mcspi_max_xfer_size;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mcspi->base = devm_ioremap_resource(&pdev->dev, r); mcspi->base = devm_ioremap_resource(&pdev->dev, r);
...@@ -1464,6 +1481,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev) ...@@ -1464,6 +1481,11 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
for (i = 0; i < master->num_chipselect; i++) { for (i = 0; i < master->num_chipselect; i++) {
sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i); sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);
sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i); sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
status = omap2_mcspi_request_dma(mcspi,
&mcspi->dma_channels[i]);
if (status == -EPROBE_DEFER)
goto free_master;
} }
status = platform_get_irq(pdev, 0); status = platform_get_irq(pdev, 0);
...@@ -1501,6 +1523,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) ...@@ -1501,6 +1523,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
free_master: free_master:
omap2_mcspi_release_dma(master);
spi_master_put(master); spi_master_put(master);
return status; return status;
} }
...@@ -1510,6 +1533,8 @@ static int omap2_mcspi_remove(struct platform_device *pdev) ...@@ -1510,6 +1533,8 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev); struct spi_master *master = platform_get_drvdata(pdev);
struct omap2_mcspi *mcspi = spi_master_get_devdata(master); struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
omap2_mcspi_release_dma(master);
pm_runtime_dont_use_autosuspend(mcspi->dev); pm_runtime_dont_use_autosuspend(mcspi->dev);
pm_runtime_put_sync(mcspi->dev); pm_runtime_put_sync(mcspi->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
......
...@@ -70,6 +70,10 @@ MODULE_ALIAS("platform:pxa2xx-spi"); ...@@ -70,6 +70,10 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define LPSS_CAPS_CS_EN_SHIFT 9 #define LPSS_CAPS_CS_EN_SHIFT 9
#define LPSS_CAPS_CS_EN_MASK (0xf << LPSS_CAPS_CS_EN_SHIFT) #define LPSS_CAPS_CS_EN_MASK (0xf << LPSS_CAPS_CS_EN_SHIFT)
#define LPSS_PRIV_CLOCK_GATE 0x38
#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK 0x3
#define LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON 0x3
struct lpss_config { struct lpss_config {
/* LPSS offset from drv_data->ioaddr */ /* LPSS offset from drv_data->ioaddr */
unsigned offset; unsigned offset;
...@@ -86,6 +90,8 @@ struct lpss_config { ...@@ -86,6 +90,8 @@ struct lpss_config {
unsigned cs_sel_shift; unsigned cs_sel_shift;
unsigned cs_sel_mask; unsigned cs_sel_mask;
unsigned cs_num; unsigned cs_num;
/* Quirks */
unsigned cs_clk_stays_gated : 1;
}; };
/* Keep these sorted with enum pxa_ssp_type */ /* Keep these sorted with enum pxa_ssp_type */
...@@ -156,6 +162,7 @@ static const struct lpss_config lpss_platforms[] = { ...@@ -156,6 +162,7 @@ static const struct lpss_config lpss_platforms[] = {
.tx_threshold_hi = 56, .tx_threshold_hi = 56,
.cs_sel_shift = 8, .cs_sel_shift = 8,
.cs_sel_mask = 3 << 8, .cs_sel_mask = 3 << 8,
.cs_clk_stays_gated = true,
}, },
}; };
...@@ -383,6 +390,22 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable) ...@@ -383,6 +390,22 @@ static void lpss_ssp_cs_control(struct spi_device *spi, bool enable)
else else
value |= LPSS_CS_CONTROL_CS_HIGH; value |= LPSS_CS_CONTROL_CS_HIGH;
__lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value); __lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
if (config->cs_clk_stays_gated) {
u32 clkgate;
/*
* Changing CS alone when dynamic clock gating is on won't
* actually flip CS at that time. This ruins SPI transfers
* that specify delays, or have no data. Toggle the clock mode
* to force on briefly to poke the CS pin to move.
*/
clkgate = __lpss_ssp_read_priv(drv_data, LPSS_PRIV_CLOCK_GATE);
value = (clkgate & ~LPSS_PRIV_CLOCK_GATE_CLK_CTL_MASK) |
LPSS_PRIV_CLOCK_GATE_CLK_CTL_FORCE_ON;
__lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, value);
__lpss_ssp_write_priv(drv_data, LPSS_PRIV_CLOCK_GATE, clkgate);
}
} }
static void cs_assert(struct spi_device *spi) static void cs_assert(struct spi_device *spi)
......
...@@ -1217,6 +1217,11 @@ static int spi_qup_suspend(struct device *device) ...@@ -1217,6 +1217,11 @@ static int spi_qup_suspend(struct device *device)
struct spi_qup *controller = spi_master_get_devdata(master); struct spi_qup *controller = spi_master_get_devdata(master);
int ret; int ret;
if (pm_runtime_suspended(device)) {
ret = spi_qup_pm_resume_runtime(device);
if (ret)
return ret;
}
ret = spi_master_suspend(master); ret = spi_master_suspend(master);
if (ret) if (ret)
return ret; return ret;
...@@ -1225,10 +1230,8 @@ static int spi_qup_suspend(struct device *device) ...@@ -1225,10 +1230,8 @@ static int spi_qup_suspend(struct device *device)
if (ret) if (ret)
return ret; return ret;
if (!pm_runtime_suspended(device)) { clk_disable_unprepare(controller->cclk);
clk_disable_unprepare(controller->cclk); clk_disable_unprepare(controller->iclk);
clk_disable_unprepare(controller->iclk);
}
return 0; return 0;
} }
......
...@@ -401,9 +401,6 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high) ...@@ -401,9 +401,6 @@ static void zynqmp_qspi_chipselect(struct spi_device *qspi, bool is_high)
zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry); zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, genfifoentry);
/* Dummy generic FIFO entry */
zynqmp_gqspi_write(xqspi, GQSPI_GEN_FIFO_OFST, 0x0);
/* Manually start the generic FIFO command */ /* Manually start the generic FIFO command */
zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST, zynqmp_gqspi_write(xqspi, GQSPI_CONFIG_OFST,
zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) | zynqmp_gqspi_read(xqspi, GQSPI_CONFIG_OFST) |
......
...@@ -2639,7 +2639,7 @@ int spi_register_controller(struct spi_controller *ctlr) ...@@ -2639,7 +2639,7 @@ int spi_register_controller(struct spi_controller *ctlr)
if (ctlr->use_gpio_descriptors) { if (ctlr->use_gpio_descriptors) {
status = spi_get_gpio_descs(ctlr); status = spi_get_gpio_descs(ctlr);
if (status) if (status)
return status; goto free_bus_id;
/* /*
* A controller using GPIO descriptors always * A controller using GPIO descriptors always
* supports SPI_CS_HIGH if need be. * supports SPI_CS_HIGH if need be.
...@@ -2649,7 +2649,7 @@ int spi_register_controller(struct spi_controller *ctlr) ...@@ -2649,7 +2649,7 @@ int spi_register_controller(struct spi_controller *ctlr)
/* Legacy code path for GPIOs from DT */ /* Legacy code path for GPIOs from DT */
status = of_spi_get_gpio_numbers(ctlr); status = of_spi_get_gpio_numbers(ctlr);
if (status) if (status)
return status; goto free_bus_id;
} }
} }
...@@ -2657,17 +2657,14 @@ int spi_register_controller(struct spi_controller *ctlr) ...@@ -2657,17 +2657,14 @@ int spi_register_controller(struct spi_controller *ctlr)
* Even if it's just one always-selected device, there must * Even if it's just one always-selected device, there must
* be at least one chipselect. * be at least one chipselect.
*/ */
if (!ctlr->num_chipselect) if (!ctlr->num_chipselect) {
return -EINVAL; status = -EINVAL;
goto free_bus_id;
}
status = device_add(&ctlr->dev); status = device_add(&ctlr->dev);
if (status < 0) { if (status < 0)
/* free bus id */ goto free_bus_id;
mutex_lock(&board_lock);
idr_remove(&spi_master_idr, ctlr->bus_num);
mutex_unlock(&board_lock);
goto done;
}
dev_dbg(dev, "registered %s %s\n", dev_dbg(dev, "registered %s %s\n",
spi_controller_is_slave(ctlr) ? "slave" : "master", spi_controller_is_slave(ctlr) ? "slave" : "master",
dev_name(&ctlr->dev)); dev_name(&ctlr->dev));
...@@ -2683,11 +2680,7 @@ int spi_register_controller(struct spi_controller *ctlr) ...@@ -2683,11 +2680,7 @@ int spi_register_controller(struct spi_controller *ctlr)
status = spi_controller_initialize_queue(ctlr); status = spi_controller_initialize_queue(ctlr);
if (status) { if (status) {
device_del(&ctlr->dev); device_del(&ctlr->dev);
/* free bus id */ goto free_bus_id;
mutex_lock(&board_lock);
idr_remove(&spi_master_idr, ctlr->bus_num);
mutex_unlock(&board_lock);
goto done;
} }
} }
/* add statistics */ /* add statistics */
...@@ -2702,7 +2695,12 @@ int spi_register_controller(struct spi_controller *ctlr) ...@@ -2702,7 +2695,12 @@ int spi_register_controller(struct spi_controller *ctlr)
/* Register devices from the device tree and ACPI */ /* Register devices from the device tree and ACPI */
of_register_spi_devices(ctlr); of_register_spi_devices(ctlr);
acpi_register_spi_devices(ctlr); acpi_register_spi_devices(ctlr);
done: return status;
free_bus_id:
mutex_lock(&board_lock);
idr_remove(&spi_master_idr, ctlr->bus_num);
mutex_unlock(&board_lock);
return status; return status;
} }
EXPORT_SYMBOL_GPL(spi_register_controller); EXPORT_SYMBOL_GPL(spi_register_controller);
......
...@@ -396,6 +396,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -396,6 +396,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
else else
retval = get_user(tmp, (u32 __user *)arg); retval = get_user(tmp, (u32 __user *)arg);
if (retval == 0) { if (retval == 0) {
struct spi_controller *ctlr = spi->controller;
u32 save = spi->mode; u32 save = spi->mode;
if (tmp & ~SPI_MODE_MASK) { if (tmp & ~SPI_MODE_MASK) {
...@@ -403,6 +404,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -403,6 +404,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
break; break;
} }
if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
ctlr->cs_gpiods[spi->chip_select])
tmp |= SPI_CS_HIGH;
tmp |= spi->mode & ~SPI_MODE_MASK; tmp |= spi->mode & ~SPI_MODE_MASK;
spi->mode = (u16)tmp; spi->mode = (u16)tmp;
retval = spi_setup(spi); retval = spi_setup(spi);
......
...@@ -11,6 +11,7 @@ struct omap2_mcspi_platform_config { ...@@ -11,6 +11,7 @@ struct omap2_mcspi_platform_config {
unsigned short num_cs; unsigned short num_cs;
unsigned int regs_offset; unsigned int regs_offset;
unsigned int pin_dir:1; unsigned int pin_dir:1;
size_t max_xfer_len;
}; };
struct omap2_mcspi_device_config { struct omap2_mcspi_device_config {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册