Merge tag 'spi-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc
Pull spi updates from Mark Brown: "No framework work here, only a bunch of driver updates of varying sizes: - Factoring out of the core hardware support from the MXS MMC driver by Marek Vasut to allow the hardware to also be used for SPI. - Lots of error handling cleanups from Guenter Roeck - Removal of the existing Tegra driver which is quite comprehensively broken as detailed in the changelog for the removal. - DT suppport for the PL022 and GPIO drivers. - pinctrl support for OMAP and PL022." Pulling from Mark Brown as Grant Likely is still busy moving. * tag 'spi-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc: (53 commits) spi: remove completely broken Tegra driver spi/imx: set the inactive state of the clock according to the clock polarity spi/pl022: get/put resources on suspend/resume spi/pl022: use more managed resources spi/pl022: Devicetree support w/o platform data spi/s3c64xx: Don't free controller_data on non-dt platforms spi: omap2-mcspi: add pinctrl support spi/pl022: adopt pinctrl support spi: omap2-mcspi: Cleanup the omap2_mcspi_txrx_dma function spi/gpio: Fix stub for spi_gpio_probe_dt() spi/mxs: Make the SPI block clock speed configurable via DT spi: spi-sh-hspi: drop frees of devm_ alloc'd data spi/pl022: Fix chipselects pointer computation spi: spi-tle62x0: Use module_spi_driver macro mxs/spi: Rework the mxs_ssp_timeout to be more readable mxs/spi: Decrement the DMA/PIO border mxs/spi: Increment the transfer length only if transfer succeeded mxs/spi: Fix issues when doing long continuous transfer spi: spi-gpio: Add DT bindings spi: spi-gpio: store chipselect information in private structure ...
This commit is contained in:
@@ -38,6 +38,8 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
@@ -140,13 +142,6 @@ struct omap2_mcspi_cs {
|
||||
u32 chconf0;
|
||||
};
|
||||
|
||||
#define MOD_REG_BIT(val, mask, set) do { \
|
||||
if (set) \
|
||||
val |= mask; \
|
||||
else \
|
||||
val &= ~mask; \
|
||||
} while (0)
|
||||
|
||||
static inline void mcspi_write_reg(struct spi_master *master,
|
||||
int idx, u32 val)
|
||||
{
|
||||
@@ -205,7 +200,11 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
|
||||
else
|
||||
rw = OMAP2_MCSPI_CHCONF_DMAW;
|
||||
|
||||
MOD_REG_BIT(l, rw, enable);
|
||||
if (enable)
|
||||
l |= rw;
|
||||
else
|
||||
l &= ~rw;
|
||||
|
||||
mcspi_write_chconf0(spi, l);
|
||||
}
|
||||
|
||||
@@ -224,7 +223,11 @@ static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
|
||||
u32 l;
|
||||
|
||||
l = mcspi_cached_chconf0(spi);
|
||||
MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active);
|
||||
if (cs_active)
|
||||
l |= OMAP2_MCSPI_CHCONF_FORCE;
|
||||
else
|
||||
l &= ~OMAP2_MCSPI_CHCONF_FORCE;
|
||||
|
||||
mcspi_write_chconf0(spi, l);
|
||||
}
|
||||
|
||||
@@ -239,9 +242,8 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master)
|
||||
* to single-channel master mode
|
||||
*/
|
||||
l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
|
||||
MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
|
||||
MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
|
||||
MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1);
|
||||
l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS);
|
||||
l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
|
||||
mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
|
||||
|
||||
ctx->modulctrl = l;
|
||||
@@ -260,16 +262,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
|
||||
list_for_each_entry(cs, &ctx->cs, node)
|
||||
__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
|
||||
}
|
||||
static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi)
|
||||
{
|
||||
pm_runtime_mark_last_busy(mcspi->dev);
|
||||
pm_runtime_put_autosuspend(mcspi->dev);
|
||||
}
|
||||
|
||||
static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi)
|
||||
{
|
||||
return pm_runtime_get_sync(mcspi->dev);
|
||||
}
|
||||
|
||||
static int omap2_prepare_transfer(struct spi_master *master)
|
||||
{
|
||||
@@ -325,6 +317,169 @@ static void omap2_mcspi_tx_callback(void *data)
|
||||
omap2_mcspi_set_dma_req(spi, 0, 0);
|
||||
}
|
||||
|
||||
static void omap2_mcspi_tx_dma(struct spi_device *spi,
|
||||
struct spi_transfer *xfer,
|
||||
struct dma_slave_config cfg)
|
||||
{
|
||||
struct omap2_mcspi *mcspi;
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
unsigned int count;
|
||||
u8 * rx;
|
||||
const u8 * tx;
|
||||
void __iomem *chstat_reg;
|
||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||
|
||||
mcspi = spi_master_get_devdata(spi->master);
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
count = xfer->len;
|
||||
|
||||
rx = xfer->rx_buf;
|
||||
tx = xfer->tx_buf;
|
||||
chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
||||
|
||||
if (mcspi_dma->dma_tx) {
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
struct scatterlist sg;
|
||||
|
||||
dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
sg_dma_address(&sg) = xfer->tx_dma;
|
||||
sg_dma_len(&sg) = xfer->len;
|
||||
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1,
|
||||
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_tx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
}
|
||||
dma_async_issue_pending(mcspi_dma->dma_tx);
|
||||
omap2_mcspi_set_dma_req(spi, 0, 1);
|
||||
|
||||
wait_for_completion(&mcspi_dma->dma_tx_completion);
|
||||
dma_unmap_single(mcspi->dev, xfer->tx_dma, count,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
/* for TX_ONLY mode, be sure all words have shifted out */
|
||||
if (rx == NULL) {
|
||||
if (mcspi_wait_for_reg_bit(chstat_reg,
|
||||
OMAP2_MCSPI_CHSTAT_TXS) < 0)
|
||||
dev_err(&spi->dev, "TXS timed out\n");
|
||||
else if (mcspi_wait_for_reg_bit(chstat_reg,
|
||||
OMAP2_MCSPI_CHSTAT_EOT) < 0)
|
||||
dev_err(&spi->dev, "EOT timed out\n");
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned
|
||||
omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||
struct dma_slave_config cfg,
|
||||
unsigned es)
|
||||
{
|
||||
struct omap2_mcspi *mcspi;
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
unsigned int count;
|
||||
u32 l;
|
||||
int elements = 0;
|
||||
int word_len, element_count;
|
||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||
mcspi = spi_master_get_devdata(spi->master);
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
count = xfer->len;
|
||||
word_len = cs->word_len;
|
||||
l = mcspi_cached_chconf0(spi);
|
||||
|
||||
if (word_len <= 8)
|
||||
element_count = count;
|
||||
else if (word_len <= 16)
|
||||
element_count = count >> 1;
|
||||
else /* word_len <= 32 */
|
||||
element_count = count >> 2;
|
||||
|
||||
if (mcspi_dma->dma_rx) {
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
struct scatterlist sg;
|
||||
size_t len = xfer->len - es;
|
||||
|
||||
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
|
||||
|
||||
if (l & OMAP2_MCSPI_CHCONF_TURBO)
|
||||
len -= es;
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
sg_dma_address(&sg) = xfer->rx_dma;
|
||||
sg_dma_len(&sg) = len;
|
||||
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
|
||||
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
|
||||
DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_rx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
}
|
||||
|
||||
dma_async_issue_pending(mcspi_dma->dma_rx);
|
||||
omap2_mcspi_set_dma_req(spi, 1, 1);
|
||||
|
||||
wait_for_completion(&mcspi_dma->dma_rx_completion);
|
||||
dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
|
||||
DMA_FROM_DEVICE);
|
||||
omap2_mcspi_set_enable(spi, 0);
|
||||
|
||||
elements = element_count - 1;
|
||||
|
||||
if (l & OMAP2_MCSPI_CHCONF_TURBO) {
|
||||
elements--;
|
||||
|
||||
if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
|
||||
& OMAP2_MCSPI_CHSTAT_RXS)) {
|
||||
u32 w;
|
||||
|
||||
w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
|
||||
if (word_len <= 8)
|
||||
((u8 *)xfer->rx_buf)[elements++] = w;
|
||||
else if (word_len <= 16)
|
||||
((u16 *)xfer->rx_buf)[elements++] = w;
|
||||
else /* word_len <= 32 */
|
||||
((u32 *)xfer->rx_buf)[elements++] = w;
|
||||
} else {
|
||||
dev_err(&spi->dev, "DMA RX penultimate word empty");
|
||||
count -= (word_len <= 8) ? 2 :
|
||||
(word_len <= 16) ? 4 :
|
||||
/* word_len <= 32 */ 8;
|
||||
omap2_mcspi_set_enable(spi, 1);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
|
||||
& OMAP2_MCSPI_CHSTAT_RXS)) {
|
||||
u32 w;
|
||||
|
||||
w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
|
||||
if (word_len <= 8)
|
||||
((u8 *)xfer->rx_buf)[elements] = w;
|
||||
else if (word_len <= 16)
|
||||
((u16 *)xfer->rx_buf)[elements] = w;
|
||||
else /* word_len <= 32 */
|
||||
((u32 *)xfer->rx_buf)[elements] = w;
|
||||
} else {
|
||||
dev_err(&spi->dev, "DMA RX last word empty");
|
||||
count -= (word_len <= 8) ? 1 :
|
||||
(word_len <= 16) ? 2 :
|
||||
/* word_len <= 32 */ 4;
|
||||
}
|
||||
omap2_mcspi_set_enable(spi, 1);
|
||||
return count;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
{
|
||||
@@ -332,12 +487,9 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||
struct omap2_mcspi_dma *mcspi_dma;
|
||||
unsigned int count;
|
||||
int word_len, element_count;
|
||||
int elements = 0;
|
||||
u32 l;
|
||||
u8 * rx;
|
||||
const u8 * tx;
|
||||
void __iomem *chstat_reg;
|
||||
u8 *rx;
|
||||
const u8 *tx;
|
||||
struct dma_slave_config cfg;
|
||||
enum dma_slave_buswidth width;
|
||||
unsigned es;
|
||||
@@ -346,7 +498,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||
l = mcspi_cached_chconf0(spi);
|
||||
|
||||
chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
||||
|
||||
if (cs->word_len <= 8) {
|
||||
width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
@@ -367,144 +518,17 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
cfg.src_maxburst = 1;
|
||||
cfg.dst_maxburst = 1;
|
||||
|
||||
if (xfer->tx_buf && mcspi_dma->dma_tx) {
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
struct scatterlist sg;
|
||||
|
||||
dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
sg_dma_address(&sg) = xfer->tx_dma;
|
||||
sg_dma_len(&sg) = xfer->len;
|
||||
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1,
|
||||
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_tx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
}
|
||||
|
||||
if (xfer->rx_buf && mcspi_dma->dma_rx) {
|
||||
struct dma_async_tx_descriptor *tx;
|
||||
struct scatterlist sg;
|
||||
size_t len = xfer->len - es;
|
||||
|
||||
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
|
||||
|
||||
if (l & OMAP2_MCSPI_CHCONF_TURBO)
|
||||
len -= es;
|
||||
|
||||
sg_init_table(&sg, 1);
|
||||
sg_dma_address(&sg) = xfer->rx_dma;
|
||||
sg_dma_len(&sg) = len;
|
||||
|
||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
|
||||
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (tx) {
|
||||
tx->callback = omap2_mcspi_rx_callback;
|
||||
tx->callback_param = spi;
|
||||
dmaengine_submit(tx);
|
||||
} else {
|
||||
/* FIXME: fall back to PIO? */
|
||||
}
|
||||
}
|
||||
|
||||
count = xfer->len;
|
||||
word_len = cs->word_len;
|
||||
|
||||
rx = xfer->rx_buf;
|
||||
tx = xfer->tx_buf;
|
||||
|
||||
if (word_len <= 8) {
|
||||
element_count = count;
|
||||
} else if (word_len <= 16) {
|
||||
element_count = count >> 1;
|
||||
} else /* word_len <= 32 */ {
|
||||
element_count = count >> 2;
|
||||
}
|
||||
count = xfer->len;
|
||||
|
||||
if (tx != NULL) {
|
||||
dma_async_issue_pending(mcspi_dma->dma_tx);
|
||||
omap2_mcspi_set_dma_req(spi, 0, 1);
|
||||
}
|
||||
if (tx != NULL)
|
||||
omap2_mcspi_tx_dma(spi, xfer, cfg);
|
||||
|
||||
if (rx != NULL) {
|
||||
dma_async_issue_pending(mcspi_dma->dma_rx);
|
||||
omap2_mcspi_set_dma_req(spi, 1, 1);
|
||||
}
|
||||
if (rx != NULL)
|
||||
return omap2_mcspi_rx_dma(spi, xfer, cfg, es);
|
||||
|
||||
if (tx != NULL) {
|
||||
wait_for_completion(&mcspi_dma->dma_tx_completion);
|
||||
dma_unmap_single(mcspi->dev, xfer->tx_dma, count,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
/* for TX_ONLY mode, be sure all words have shifted out */
|
||||
if (rx == NULL) {
|
||||
if (mcspi_wait_for_reg_bit(chstat_reg,
|
||||
OMAP2_MCSPI_CHSTAT_TXS) < 0)
|
||||
dev_err(&spi->dev, "TXS timed out\n");
|
||||
else if (mcspi_wait_for_reg_bit(chstat_reg,
|
||||
OMAP2_MCSPI_CHSTAT_EOT) < 0)
|
||||
dev_err(&spi->dev, "EOT timed out\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (rx != NULL) {
|
||||
wait_for_completion(&mcspi_dma->dma_rx_completion);
|
||||
dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
|
||||
DMA_FROM_DEVICE);
|
||||
omap2_mcspi_set_enable(spi, 0);
|
||||
|
||||
elements = element_count - 1;
|
||||
|
||||
if (l & OMAP2_MCSPI_CHCONF_TURBO) {
|
||||
elements--;
|
||||
|
||||
if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
|
||||
& OMAP2_MCSPI_CHSTAT_RXS)) {
|
||||
u32 w;
|
||||
|
||||
w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
|
||||
if (word_len <= 8)
|
||||
((u8 *)xfer->rx_buf)[elements++] = w;
|
||||
else if (word_len <= 16)
|
||||
((u16 *)xfer->rx_buf)[elements++] = w;
|
||||
else /* word_len <= 32 */
|
||||
((u32 *)xfer->rx_buf)[elements++] = w;
|
||||
} else {
|
||||
dev_err(&spi->dev,
|
||||
"DMA RX penultimate word empty");
|
||||
count -= (word_len <= 8) ? 2 :
|
||||
(word_len <= 16) ? 4 :
|
||||
/* word_len <= 32 */ 8;
|
||||
omap2_mcspi_set_enable(spi, 1);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
|
||||
& OMAP2_MCSPI_CHSTAT_RXS)) {
|
||||
u32 w;
|
||||
|
||||
w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
|
||||
if (word_len <= 8)
|
||||
((u8 *)xfer->rx_buf)[elements] = w;
|
||||
else if (word_len <= 16)
|
||||
((u16 *)xfer->rx_buf)[elements] = w;
|
||||
else /* word_len <= 32 */
|
||||
((u32 *)xfer->rx_buf)[elements] = w;
|
||||
} else {
|
||||
dev_err(&spi->dev, "DMA RX last word empty");
|
||||
count -= (word_len <= 8) ? 1 :
|
||||
(word_len <= 16) ? 2 :
|
||||
/* word_len <= 32 */ 4;
|
||||
}
|
||||
omap2_mcspi_set_enable(spi, 1);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -848,12 +872,13 @@ static int omap2_mcspi_setup(struct spi_device *spi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = omap2_mcspi_enable_clocks(mcspi);
|
||||
ret = pm_runtime_get_sync(mcspi->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = omap2_mcspi_setup_transfer(spi, NULL);
|
||||
omap2_mcspi_disable_clocks(mcspi);
|
||||
pm_runtime_mark_last_busy(mcspi->dev);
|
||||
pm_runtime_put_autosuspend(mcspi->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1067,7 +1092,7 @@ static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
|
||||
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
|
||||
int ret = 0;
|
||||
|
||||
ret = omap2_mcspi_enable_clocks(mcspi);
|
||||
ret = pm_runtime_get_sync(mcspi->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -1076,7 +1101,8 @@ static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
|
||||
ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
|
||||
|
||||
omap2_mcspi_set_master_mode(master);
|
||||
omap2_mcspi_disable_clocks(mcspi);
|
||||
pm_runtime_mark_last_busy(mcspi->dev);
|
||||
pm_runtime_put_autosuspend(mcspi->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1124,6 +1150,7 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
|
||||
static int bus_num = 1;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
const struct of_device_id *match;
|
||||
struct pinctrl *pinctrl;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
|
||||
if (master == NULL) {
|
||||
@@ -1219,6 +1246,11 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
|
||||
if (status < 0)
|
||||
goto dma_chnl_free;
|
||||
|
||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl))
|
||||
dev_warn(&pdev->dev,
|
||||
"pins are not configured from the driver\n");
|
||||
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
@@ -1238,7 +1270,6 @@ dma_chnl_free:
|
||||
kfree(mcspi->dma_channels);
|
||||
free_master:
|
||||
spi_master_put(master);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1252,12 +1283,11 @@ static int __devexit omap2_mcspi_remove(struct platform_device *pdev)
|
||||
mcspi = spi_master_get_devdata(master);
|
||||
dma_channels = mcspi->dma_channels;
|
||||
|
||||
omap2_mcspi_disable_clocks(mcspi);
|
||||
pm_runtime_put_sync(mcspi->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
spi_unregister_master(master);
|
||||
kfree(dma_channels);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1278,20 +1308,21 @@ static int omap2_mcspi_resume(struct device *dev)
|
||||
struct omap2_mcspi_regs *ctx = &mcspi->ctx;
|
||||
struct omap2_mcspi_cs *cs;
|
||||
|
||||
omap2_mcspi_enable_clocks(mcspi);
|
||||
pm_runtime_get_sync(mcspi->dev);
|
||||
list_for_each_entry(cs, &ctx->cs, node) {
|
||||
if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
|
||||
/*
|
||||
* We need to toggle CS state for OMAP take this
|
||||
* change in account.
|
||||
*/
|
||||
MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1);
|
||||
cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE;
|
||||
__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
|
||||
MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0);
|
||||
cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
|
||||
__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
|
||||
}
|
||||
}
|
||||
omap2_mcspi_disable_clocks(mcspi);
|
||||
pm_runtime_mark_last_busy(mcspi->dev);
|
||||
pm_runtime_put_autosuspend(mcspi->dev);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
Reference in New Issue
Block a user