spi: Updates for v3.11
A fairly quiet release for the SPI subsystem, the standout changes being: - Core support for implementing bits per word constraints implemented by Stephen Warren, factoring some code out of drivers. - Addition of polling mode support for the s3c64xx driver as some newer Exynos systems have taken the unusual step of removing interrupt support. - Use of the in-IP FIFO and generic dmaengine support for the OMAP2 driver, providing improved performance. - Conversion of the mpc512x driver to use the core message queue infrastructure. The nicest thing being that all the factoring out into common code leads to a negative diffstat overall. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJR0U1DAAoJELSic+t+oim9sX4P/08KgncJt5ELjAmMosmBProl anfDekjNTmtSVkPX/RKahszGWhKy77xlFE+gSjkxtdlZoKYbtQpTpgIyN5HbpfSO OWAZZFX+rC7F64qw081cXWrjtT1LtOY8KpbPtJQa/uHQzpEYkhpMcwtp/e3QBnHp lrRzIjViDMqhOvPxMNEI3orQ3fmB8K+hlnCYkakGZ4osXdVkitHfW16xEHyRNFxi s4SD2wVhAAg5z1H09rHRVcvYFJop0bRLMATXItYgsGXGpIjSQpZ+Px+pfD0Gxtzq Xy16hmX5s4hmpMflOEXIxGSUURHF/5/qcBNawz12PL3Godie+D0iZvYGx6tJlj06 W8PsVqDa+oKitC+q4OQQbfFgOltP73MR2LwvvNRFiwzccahhAFyoZXzy8Duuewsm I+A1k1vyGdmqmVGzwsP8ly2ad+eQftdhBKUj4XcOpPzcOQU2nG6+YZHb3OLKpKlt pCAFvckbJWMhfRN14B/9loXd1lHwVt3yvX0Q8fWM3FnyguON6rhTNsDWwjcqOo6S fyI//C0ENMwTzvZuOTOkc32XiNYIgZ1ksmICeCaxsfEXrTRMLvyPhfil4d6yUTrb TCpgQIsfuBTJXkJTf6Ggj9G9xmi3yx6XCh7sU8/55VmPGwreCbxwfHfnDOauZuoK jRIg2Bjm/Ckf4hJZ6jPs =/2eV -----END PGP SIGNATURE----- Merge tag 'spi-v3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi updates from Mark Brown: "A fairly quiet release for the SPI subsystem, the standout changes being: - Core support for implementing bits per word constraints implemented by Stephen Warren, factoring some code out of drivers. - Addition of polling mode support for the s3c64xx driver as some newer Exynos systems have taken the unusual step of removing interrupt support. - Use of the in-IP FIFO and generic dmaengine support for the OMAP2 driver, providing improved performance. - Conversion of the mpc512x driver to use the core message queue infrastructure. The nicest thing being that all the factoring out into common code leads to a negative diffstat overall." * tag 'spi-v3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (42 commits) spi/s3c64xx: Rely on the compiler eliminating the OF ID table spi: s3c64xx: Added support for exynos5440 spi spi: s3c64xx: Added provision for dedicated cs pin spi: omap2-mcspi: add generic DMA request support to the DT binding spi: omap2-mcspi: convert to dma_request_slave_channel_compat() spi/s3c64xx: Make wait_for_timeout() function name less generic spi: s3c64xx: added support for polling mode spi: omap2-mcspi: Add FIFO buffer support spi: omap2-mcspi: Move bytes per word calculation to the function spi: spi-xilinx: cleanup a check in xilinx_spi_txrx_bufs() spi: spi-nuc900: Remove redundant platform_set_drvdata() spi: spi-fsl-lib: Make mpc8xxx_spi_work static spi: spi-topcliff-pch: Fix sparse warnings spi: spi-xilinx: Remove redundant platform_set_drvdata() spi: spi-xilinx: Add run run-time endian detection spi: mpc512x: use the SPI subsystem's message queue spi: mpc512x: improve throughput in the RX/TX func spi: mpc512x: minor prep before feature change spi: atmel: convert to dma_request_slave_channel_compat() spi: sirf: avoid uninitialized-use warning ...
This commit is contained in:
commit
750b2d7b93
|
@ -10,7 +10,18 @@ Required properties:
|
||||||
input. The default is D0 as input and
|
input. The default is D0 as input and
|
||||||
D1 as output.
|
D1 as output.
|
||||||
|
|
||||||
Example:
|
Optional properties:
|
||||||
|
- dmas: List of DMA specifiers with the controller specific format
|
||||||
|
as described in the generic DMA client binding. A tx and rx
|
||||||
|
specifier is required for each chip select.
|
||||||
|
- dma-names: List of DMA request names. These strings correspond
|
||||||
|
1:1 with the DMA specifiers listed in dmas. The string naming
|
||||||
|
is to be "rxN" and "txN" for RX and TX requests,
|
||||||
|
respectively, where N equals the chip select number.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
[hwmod populated DMA resources]
|
||||||
|
|
||||||
mcspi1: mcspi@1 {
|
mcspi1: mcspi@1 {
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
|
@ -20,3 +31,17 @@ mcspi1: mcspi@1 {
|
||||||
ti,spi-num-cs = <4>;
|
ti,spi-num-cs = <4>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[generic DMA request binding]
|
||||||
|
|
||||||
|
mcspi1: mcspi@1 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
compatible = "ti,omap4-mcspi";
|
||||||
|
ti,hwmods = "mcspi1";
|
||||||
|
ti,spi-num-cs = <2>;
|
||||||
|
dmas = <&edma 42
|
||||||
|
&edma 43
|
||||||
|
&edma 44
|
||||||
|
&edma 45>;
|
||||||
|
dma-names = "tx0", "rx0", "tx1", "rx1";
|
||||||
|
};
|
||||||
|
|
|
@ -145,7 +145,6 @@ static struct spi_board_info timberdale_spi_8bit_board_info[] = {
|
||||||
|
|
||||||
static struct xspi_platform_data timberdale_xspi_platform_data = {
|
static struct xspi_platform_data timberdale_xspi_platform_data = {
|
||||||
.num_chipselect = 3,
|
.num_chipselect = 3,
|
||||||
.little_endian = true,
|
|
||||||
/* bits per word and devices will be filled in runtime depending
|
/* bits per word and devices will be filled in runtime depending
|
||||||
* on the HW config
|
* on the HW config
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -103,16 +103,6 @@ static void altera_spi_chipsel(struct spi_device *spi, int value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int altera_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int altera_spi_setup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
|
static inline unsigned int hw_txbyte(struct altera_spi *hw, int count)
|
||||||
{
|
{
|
||||||
if (hw->tx) {
|
if (hw->tx) {
|
||||||
|
@ -231,7 +221,6 @@ static int altera_spi_probe(struct platform_device *pdev)
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = 16;
|
master->num_chipselect = 16;
|
||||||
master->mode_bits = SPI_CS_HIGH;
|
master->mode_bits = SPI_CS_HIGH;
|
||||||
master->setup = altera_spi_setup;
|
|
||||||
|
|
||||||
hw = spi_master_get_devdata(master);
|
hw = spi_master_get_devdata(master);
|
||||||
platform_set_drvdata(pdev, hw);
|
platform_set_drvdata(pdev, hw);
|
||||||
|
@ -240,7 +229,6 @@ static int altera_spi_probe(struct platform_device *pdev)
|
||||||
hw->bitbang.master = spi_master_get(master);
|
hw->bitbang.master = spi_master_get(master);
|
||||||
if (!hw->bitbang.master)
|
if (!hw->bitbang.master)
|
||||||
return err;
|
return err;
|
||||||
hw->bitbang.setup_transfer = altera_spi_setupxfer;
|
|
||||||
hw->bitbang.chipselect = altera_spi_chipsel;
|
hw->bitbang.chipselect = altera_spi_chipsel;
|
||||||
hw->bitbang.txrx_bufs = altera_spi_txrx;
|
hw->bitbang.txrx_bufs = altera_spi_txrx;
|
||||||
|
|
||||||
|
@ -285,7 +273,6 @@ static int altera_spi_probe(struct platform_device *pdev)
|
||||||
exit_busy:
|
exit_busy:
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
exit:
|
exit:
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -296,7 +283,6 @@ static int altera_spi_remove(struct platform_device *dev)
|
||||||
struct spi_master *master = hw->bitbang.master;
|
struct spi_master *master = hw->bitbang.master;
|
||||||
|
|
||||||
spi_bitbang_stop(&hw->bitbang);
|
spi_bitbang_stop(&hw->bitbang);
|
||||||
platform_set_drvdata(dev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,9 +155,6 @@ static int ath79_spi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
if (spi->bits_per_word > 32)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!spi->controller_state) {
|
if (!spi->controller_state) {
|
||||||
status = ath79_spi_setup_cs(spi);
|
status = ath79_spi_setup_cs(spi);
|
||||||
if (status)
|
if (status)
|
||||||
|
@ -226,6 +223,7 @@ static int ath79_spi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
pdata = pdev->dev.platform_data;
|
pdata = pdev->dev.platform_data;
|
||||||
|
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
|
||||||
master->setup = ath79_spi_setup;
|
master->setup = ath79_spi_setup;
|
||||||
master->cleanup = ath79_spi_cleanup;
|
master->cleanup = ath79_spi_cleanup;
|
||||||
if (pdata) {
|
if (pdata) {
|
||||||
|
@ -287,7 +285,6 @@ err_clk_put:
|
||||||
err_unmap:
|
err_unmap:
|
||||||
iounmap(sp->base);
|
iounmap(sp->base);
|
||||||
err_put_master:
|
err_put_master:
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_master_put(sp->bitbang.master);
|
spi_master_put(sp->bitbang.master);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -302,7 +299,6 @@ static int ath79_spi_remove(struct platform_device *pdev)
|
||||||
clk_disable(sp->clk);
|
clk_disable(sp->clk);
|
||||||
clk_put(sp->clk);
|
clk_put(sp->clk);
|
||||||
iounmap(sp->base);
|
iounmap(sp->base);
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_master_put(sp->bitbang.master);
|
spi_master_put(sp->bitbang.master);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -424,10 +424,15 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool filter(struct dma_chan *chan, void *slave)
|
static bool filter(struct dma_chan *chan, void *pdata)
|
||||||
{
|
{
|
||||||
struct at_dma_slave *sl = slave;
|
struct atmel_spi_dma *sl_pdata = pdata;
|
||||||
|
struct at_dma_slave *sl;
|
||||||
|
|
||||||
|
if (!sl_pdata)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sl = &sl_pdata->dma_slave;
|
||||||
if (sl->dma_dev == chan->device->dev) {
|
if (sl->dma_dev == chan->device->dev) {
|
||||||
chan->private = sl;
|
chan->private = sl;
|
||||||
return true;
|
return true;
|
||||||
|
@ -438,24 +443,31 @@ static bool filter(struct dma_chan *chan, void *slave)
|
||||||
|
|
||||||
static int atmel_spi_configure_dma(struct atmel_spi *as)
|
static int atmel_spi_configure_dma(struct atmel_spi *as)
|
||||||
{
|
{
|
||||||
struct at_dma_slave *sdata = &as->dma.dma_slave;
|
|
||||||
struct dma_slave_config slave_config;
|
struct dma_slave_config slave_config;
|
||||||
|
struct device *dev = &as->pdev->dev;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (sdata && sdata->dma_dev) {
|
|
||||||
dma_cap_mask_t mask;
|
dma_cap_mask_t mask;
|
||||||
|
|
||||||
/* Try to grab two DMA channels */
|
|
||||||
dma_cap_zero(mask);
|
dma_cap_zero(mask);
|
||||||
dma_cap_set(DMA_SLAVE, mask);
|
dma_cap_set(DMA_SLAVE, mask);
|
||||||
as->dma.chan_tx = dma_request_channel(mask, filter, sdata);
|
|
||||||
if (as->dma.chan_tx)
|
as->dma.chan_tx = dma_request_slave_channel_compat(mask, filter,
|
||||||
as->dma.chan_rx =
|
&as->dma,
|
||||||
dma_request_channel(mask, filter, sdata);
|
dev, "tx");
|
||||||
|
if (!as->dma.chan_tx) {
|
||||||
|
dev_err(dev,
|
||||||
|
"DMA TX channel not available, SPI unable to use DMA\n");
|
||||||
|
err = -EBUSY;
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
if (!as->dma.chan_rx || !as->dma.chan_tx) {
|
|
||||||
dev_err(&as->pdev->dev,
|
as->dma.chan_rx = dma_request_slave_channel_compat(mask, filter,
|
||||||
"DMA channel not available, SPI unable to use DMA\n");
|
&as->dma,
|
||||||
|
dev, "rx");
|
||||||
|
|
||||||
|
if (!as->dma.chan_rx) {
|
||||||
|
dev_err(dev,
|
||||||
|
"DMA RX channel not available, SPI unable to use DMA\n");
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -1268,13 +1280,6 @@ static int atmel_spi_setup(struct spi_device *spi)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bits < 8 || bits > 16) {
|
|
||||||
dev_dbg(&spi->dev,
|
|
||||||
"setup: invalid bits_per_word %u (8 to 16)\n",
|
|
||||||
bits);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* see notes above re chipselect */
|
/* see notes above re chipselect */
|
||||||
if (!atmel_spi_is_v2(as)
|
if (!atmel_spi_is_v2(as)
|
||||||
&& spi->chip_select == 0
|
&& spi->chip_select == 0
|
||||||
|
@ -1515,7 +1520,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
/* the spi->mode bits understood by this driver: */
|
/* the spi->mode bits understood by this driver: */
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
|
||||||
master->dev.of_node = pdev->dev.of_node;
|
master->dev.of_node = pdev->dev.of_node;
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = master->dev.of_node ? 0 : 4;
|
master->num_chipselect = master->dev.of_node ? 0 : 4;
|
||||||
|
|
|
@ -248,11 +248,6 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
|
||||||
hz = t->speed_hz;
|
hz = t->speed_hz;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bpw < 4 || bpw > 24) {
|
|
||||||
dev_err(&spi->dev, "setupxfer: invalid bits_per_word=%d\n",
|
|
||||||
bpw);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
|
if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
|
||||||
dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",
|
dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",
|
||||||
hz);
|
hz);
|
||||||
|
@ -296,12 +291,6 @@ static int au1550_spi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
|
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
|
||||||
|
|
||||||
if (spi->bits_per_word < 4 || spi->bits_per_word > 24) {
|
|
||||||
dev_err(&spi->dev, "setup: invalid bits_per_word=%d\n",
|
|
||||||
spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spi->max_speed_hz == 0)
|
if (spi->max_speed_hz == 0)
|
||||||
spi->max_speed_hz = hw->freq_max;
|
spi->max_speed_hz = hw->freq_max;
|
||||||
if (spi->max_speed_hz > hw->freq_max
|
if (spi->max_speed_hz > hw->freq_max
|
||||||
|
@ -782,6 +771,7 @@ static int au1550_spi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
/* the spi->mode bits understood by this driver: */
|
/* the spi->mode bits understood by this driver: */
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 24);
|
||||||
|
|
||||||
hw = spi_master_get_devdata(master);
|
hw = spi_master_get_devdata(master);
|
||||||
|
|
||||||
|
@ -987,8 +977,6 @@ static int au1550_spi_remove(struct platform_device *pdev)
|
||||||
au1xxx_dbdma_chan_free(hw->dma_tx_ch);
|
au1xxx_dbdma_chan_free(hw->dma_tx_ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
spi_master_put(hw->master);
|
spi_master_put(hw->master);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -331,10 +331,9 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
|
||||||
goto out_master_put;
|
goto out_master_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->regs = devm_request_and_ioremap(&pdev->dev, res);
|
bs->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (!bs->regs) {
|
if (IS_ERR(bs->regs)) {
|
||||||
dev_err(&pdev->dev, "could not request/map memory region\n");
|
err = PTR_ERR(bs->regs);
|
||||||
err = -ENODEV;
|
|
||||||
goto out_master_put;
|
goto out_master_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,17 +124,6 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
|
||||||
/* the spi->mode bits understood by this driver: */
|
/* the spi->mode bits understood by this driver: */
|
||||||
#define MODEBITS (SPI_CPOL | SPI_CPHA)
|
#define MODEBITS (SPI_CPOL | SPI_CPHA)
|
||||||
|
|
||||||
static int bcm63xx_spi_setup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
if (spi->bits_per_word != 8) {
|
|
||||||
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
|
|
||||||
__func__, spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
|
static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
|
||||||
unsigned int num_transfers)
|
unsigned int num_transfers)
|
||||||
{
|
{
|
||||||
|
@ -277,13 +266,6 @@ static int bcm63xx_spi_transfer_one(struct spi_master *master,
|
||||||
* full-duplex transfers.
|
* full-duplex transfers.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||||
if (t->bits_per_word != 8) {
|
|
||||||
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
|
|
||||||
__func__, t->bits_per_word);
|
|
||||||
status = -EINVAL;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!first)
|
if (!first)
|
||||||
first = t;
|
first = t;
|
||||||
|
|
||||||
|
@ -430,11 +412,11 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
master->bus_num = pdata->bus_num;
|
master->bus_num = pdata->bus_num;
|
||||||
master->num_chipselect = pdata->num_chipselect;
|
master->num_chipselect = pdata->num_chipselect;
|
||||||
master->setup = bcm63xx_spi_setup;
|
|
||||||
master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer;
|
master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer;
|
||||||
master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
|
master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
|
||||||
master->transfer_one_message = bcm63xx_spi_transfer_one;
|
master->transfer_one_message = bcm63xx_spi_transfer_one;
|
||||||
master->mode_bits = MODEBITS;
|
master->mode_bits = MODEBITS;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||||
bs->msg_type_shift = pdata->msg_type_shift;
|
bs->msg_type_shift = pdata->msg_type_shift;
|
||||||
bs->msg_ctl_width = pdata->msg_ctl_width;
|
bs->msg_ctl_width = pdata->msg_ctl_width;
|
||||||
bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
|
bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
|
||||||
|
@ -469,7 +451,6 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
|
||||||
out_clk_disable:
|
out_clk_disable:
|
||||||
clk_disable_unprepare(clk);
|
clk_disable_unprepare(clk);
|
||||||
out_err:
|
out_err:
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
out_clk:
|
out_clk:
|
||||||
clk_put(clk);
|
clk_put(clk);
|
||||||
|
@ -491,8 +472,6 @@ static int bcm63xx_spi_remove(struct platform_device *pdev)
|
||||||
clk_disable_unprepare(bs->clk);
|
clk_disable_unprepare(bs->clk);
|
||||||
clk_put(bs->clk);
|
clk_put(bs->clk);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, 0);
|
|
||||||
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -417,7 +417,7 @@ bfin_sport_spi_pump_transfers(unsigned long data)
|
||||||
|
|
||||||
/* Bits per word setup */
|
/* Bits per word setup */
|
||||||
bits_per_word = transfer->bits_per_word;
|
bits_per_word = transfer->bits_per_word;
|
||||||
if (bits_per_word % 16 == 0)
|
if (bits_per_word == 16)
|
||||||
drv_data->ops = &bfin_sport_transfer_ops_u16;
|
drv_data->ops = &bfin_sport_transfer_ops_u16;
|
||||||
else
|
else
|
||||||
drv_data->ops = &bfin_sport_transfer_ops_u8;
|
drv_data->ops = &bfin_sport_transfer_ops_u8;
|
||||||
|
@ -600,13 +600,6 @@ bfin_sport_spi_setup(struct spi_device *spi)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spi->bits_per_word % 8) {
|
|
||||||
dev_err(&spi->dev, "%d bits_per_word is not supported\n",
|
|
||||||
spi->bits_per_word);
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* translate common spi framework into our register
|
/* translate common spi framework into our register
|
||||||
* following configure contents are same for tx and rx.
|
* following configure contents are same for tx and rx.
|
||||||
*/
|
*/
|
||||||
|
@ -778,6 +771,7 @@ static int bfin_sport_spi_probe(struct platform_device *pdev)
|
||||||
drv_data->pin_req = platform_info->pin_req;
|
drv_data->pin_req = platform_info->pin_req;
|
||||||
|
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = platform_info->num_chipselect;
|
master->num_chipselect = platform_info->num_chipselect;
|
||||||
master->cleanup = bfin_sport_spi_cleanup;
|
master->cleanup = bfin_sport_spi_cleanup;
|
||||||
|
@ -882,9 +876,6 @@ static int bfin_sport_spi_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
peripheral_free_list(drv_data->pin_req);
|
peripheral_free_list(drv_data->pin_req);
|
||||||
|
|
||||||
/* Prevent double remove */
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -643,21 +643,16 @@ static void bfin_spi_pump_transfers(unsigned long data)
|
||||||
|
|
||||||
/* Bits per word setup */
|
/* Bits per word setup */
|
||||||
bits_per_word = transfer->bits_per_word;
|
bits_per_word = transfer->bits_per_word;
|
||||||
if (bits_per_word % 16 == 0) {
|
if (bits_per_word == 16) {
|
||||||
drv_data->n_bytes = bits_per_word/8;
|
drv_data->n_bytes = bits_per_word/8;
|
||||||
drv_data->len = (transfer->len) >> 1;
|
drv_data->len = (transfer->len) >> 1;
|
||||||
cr_width = BIT_CTL_WORDSIZE;
|
cr_width = BIT_CTL_WORDSIZE;
|
||||||
drv_data->ops = &bfin_bfin_spi_transfer_ops_u16;
|
drv_data->ops = &bfin_bfin_spi_transfer_ops_u16;
|
||||||
} else if (bits_per_word % 8 == 0) {
|
} else if (bits_per_word == 8) {
|
||||||
drv_data->n_bytes = bits_per_word/8;
|
drv_data->n_bytes = bits_per_word/8;
|
||||||
drv_data->len = transfer->len;
|
drv_data->len = transfer->len;
|
||||||
cr_width = 0;
|
cr_width = 0;
|
||||||
drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
|
drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
|
||||||
} else {
|
|
||||||
dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n");
|
|
||||||
message->status = -EINVAL;
|
|
||||||
bfin_spi_giveback(drv_data);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
cr = bfin_read(&drv_data->regs->ctl) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
|
cr = bfin_read(&drv_data->regs->ctl) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
|
||||||
cr |= cr_width;
|
cr |= cr_width;
|
||||||
|
@ -808,13 +803,13 @@ static void bfin_spi_pump_transfers(unsigned long data)
|
||||||
bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val);
|
bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val);
|
||||||
else {
|
else {
|
||||||
int loop;
|
int loop;
|
||||||
if (bits_per_word % 16 == 0) {
|
if (bits_per_word == 16) {
|
||||||
u16 *buf = (u16 *)drv_data->tx;
|
u16 *buf = (u16 *)drv_data->tx;
|
||||||
for (loop = 0; loop < bits_per_word / 16;
|
for (loop = 0; loop < bits_per_word / 16;
|
||||||
loop++) {
|
loop++) {
|
||||||
bfin_write(&drv_data->regs->tdbr, *buf++);
|
bfin_write(&drv_data->regs->tdbr, *buf++);
|
||||||
}
|
}
|
||||||
} else if (bits_per_word % 8 == 0) {
|
} else if (bits_per_word == 8) {
|
||||||
u8 *buf = (u8 *)drv_data->tx;
|
u8 *buf = (u8 *)drv_data->tx;
|
||||||
for (loop = 0; loop < bits_per_word / 8; loop++)
|
for (loop = 0; loop < bits_per_word / 8; loop++)
|
||||||
bfin_write(&drv_data->regs->tdbr, *buf++);
|
bfin_write(&drv_data->regs->tdbr, *buf++);
|
||||||
|
@ -1033,12 +1028,6 @@ static int bfin_spi_setup(struct spi_device *spi)
|
||||||
chip->ctl_reg &= bfin_ctl_reg;
|
chip->ctl_reg &= bfin_ctl_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spi->bits_per_word % 8) {
|
|
||||||
dev_err(&spi->dev, "%d bits_per_word is not supported\n",
|
|
||||||
spi->bits_per_word);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* translate common spi framework into our register */
|
/* translate common spi framework into our register */
|
||||||
if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
|
if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
|
||||||
dev_err(&spi->dev, "unsupported spi modes detected\n");
|
dev_err(&spi->dev, "unsupported spi modes detected\n");
|
||||||
|
@ -1299,7 +1288,7 @@ static int bfin_spi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
/* the spi->mode bits supported by this driver: */
|
/* the spi->mode bits supported by this driver: */
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = platform_info->num_chipselect;
|
master->num_chipselect = platform_info->num_chipselect;
|
||||||
master->cleanup = bfin_spi_cleanup;
|
master->cleanup = bfin_spi_cleanup;
|
||||||
|
@ -1418,9 +1407,6 @@ static int bfin_spi_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
peripheral_free_list(drv_data->pin_req);
|
peripheral_free_list(drv_data->pin_req);
|
||||||
|
|
||||||
/* Prevent double remove */
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,12 +42,6 @@ static int spi_clps711x_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
|
struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
|
||||||
|
|
||||||
if (spi->bits_per_word != 8) {
|
|
||||||
dev_err(&spi->dev, "Unsupported master bus width %i\n",
|
|
||||||
spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We are expect that SPI-device is not selected */
|
/* We are expect that SPI-device is not selected */
|
||||||
gpio_direction_output(hw->chipselect[spi->chip_select],
|
gpio_direction_output(hw->chipselect[spi->chip_select],
|
||||||
!(spi->mode & SPI_CS_HIGH));
|
!(spi->mode & SPI_CS_HIGH));
|
||||||
|
@ -190,6 +184,7 @@ static int spi_clps711x_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
|
master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||||
master->num_chipselect = pdata->num_chipselect;
|
master->num_chipselect = pdata->num_chipselect;
|
||||||
master->setup = spi_clps711x_setup;
|
master->setup = spi_clps711x_setup;
|
||||||
master->transfer_one_message = spi_clps711x_transfer_one_message;
|
master->transfer_one_message = spi_clps711x_transfer_one_message;
|
||||||
|
@ -254,7 +249,6 @@ err_out:
|
||||||
if (gpio_is_valid(hw->chipselect[i]))
|
if (gpio_is_valid(hw->chipselect[i]))
|
||||||
gpio_free(hw->chipselect[i]);
|
gpio_free(hw->chipselect[i]);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
kfree(master);
|
kfree(master);
|
||||||
|
|
||||||
|
@ -274,7 +268,6 @@ static int spi_clps711x_remove(struct platform_device *pdev)
|
||||||
gpio_free(hw->chipselect[i]);
|
gpio_free(hw->chipselect[i]);
|
||||||
|
|
||||||
devm_clk_put(&pdev->dev, hw->spi_clk);
|
devm_clk_put(&pdev->dev, hw->spi_clk);
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_unregister_master(master);
|
spi_unregister_master(master);
|
||||||
kfree(master);
|
kfree(master);
|
||||||
|
|
||||||
|
|
|
@ -312,10 +312,7 @@ static int mcfqspi_transfer_one_message(struct spi_master *master,
|
||||||
bool cs_high = spi->mode & SPI_CS_HIGH;
|
bool cs_high = spi->mode & SPI_CS_HIGH;
|
||||||
u16 qmr = MCFQSPI_QMR_MSTR;
|
u16 qmr = MCFQSPI_QMR_MSTR;
|
||||||
|
|
||||||
if (t->bits_per_word)
|
|
||||||
qmr |= t->bits_per_word << 10;
|
qmr |= t->bits_per_word << 10;
|
||||||
else
|
|
||||||
qmr |= spi->bits_per_word << 10;
|
|
||||||
if (spi->mode & SPI_CPHA)
|
if (spi->mode & SPI_CPHA)
|
||||||
qmr |= MCFQSPI_QMR_CPHA;
|
qmr |= MCFQSPI_QMR_CPHA;
|
||||||
if (spi->mode & SPI_CPOL)
|
if (spi->mode & SPI_CPOL)
|
||||||
|
@ -377,11 +374,6 @@ static int mcfqspi_unprepare_transfer_hw(struct spi_master *master)
|
||||||
|
|
||||||
static int mcfqspi_setup(struct spi_device *spi)
|
static int mcfqspi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
if ((spi->bits_per_word < 8) || (spi->bits_per_word > 16)) {
|
|
||||||
dev_dbg(&spi->dev, "%d bits per word is not supported\n",
|
|
||||||
spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (spi->chip_select >= spi->master->num_chipselect) {
|
if (spi->chip_select >= spi->master->num_chipselect) {
|
||||||
dev_dbg(&spi->dev, "%d chip select is out of range\n",
|
dev_dbg(&spi->dev, "%d chip select is out of range\n",
|
||||||
spi->chip_select);
|
spi->chip_select);
|
||||||
|
@ -408,6 +400,12 @@ static int mcfqspi_probe(struct platform_device *pdev)
|
||||||
struct mcfqspi_platform_data *pdata;
|
struct mcfqspi_platform_data *pdata;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
pdata = pdev->dev.platform_data;
|
||||||
|
if (!pdata) {
|
||||||
|
dev_dbg(&pdev->dev, "platform data is missing\n");
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
|
master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
|
||||||
if (master == NULL) {
|
if (master == NULL) {
|
||||||
dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
|
dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
|
||||||
|
@ -458,11 +456,6 @@ static int mcfqspi_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
clk_enable(mcfqspi->clk);
|
clk_enable(mcfqspi->clk);
|
||||||
|
|
||||||
pdata = pdev->dev.platform_data;
|
|
||||||
if (!pdata) {
|
|
||||||
dev_dbg(&pdev->dev, "platform data is missing\n");
|
|
||||||
goto fail4;
|
|
||||||
}
|
|
||||||
master->bus_num = pdata->bus_num;
|
master->bus_num = pdata->bus_num;
|
||||||
master->num_chipselect = pdata->num_chipselect;
|
master->num_chipselect = pdata->num_chipselect;
|
||||||
|
|
||||||
|
@ -477,6 +470,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
|
||||||
mcfqspi->dev = &pdev->dev;
|
mcfqspi->dev = &pdev->dev;
|
||||||
|
|
||||||
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
|
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
|
||||||
master->setup = mcfqspi_setup;
|
master->setup = mcfqspi_setup;
|
||||||
master->transfer_one_message = mcfqspi_transfer_one_message;
|
master->transfer_one_message = mcfqspi_transfer_one_message;
|
||||||
master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw;
|
master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw;
|
||||||
|
@ -524,7 +518,6 @@ static int mcfqspi_remove(struct platform_device *pdev)
|
||||||
/* disable the hardware (set the baud rate to 0) */
|
/* disable the hardware (set the baud rate to 0) */
|
||||||
mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
|
mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
mcfqspi_cs_teardown(mcfqspi);
|
mcfqspi_cs_teardown(mcfqspi);
|
||||||
clk_disable(mcfqspi->clk);
|
clk_disable(mcfqspi->clk);
|
||||||
clk_put(mcfqspi->clk);
|
clk_put(mcfqspi->clk);
|
||||||
|
|
|
@ -299,16 +299,15 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
|
||||||
* Assign function pointer to appropriate transfer method
|
* Assign function pointer to appropriate transfer method
|
||||||
* 8bit, 16bit or 32bit transfer
|
* 8bit, 16bit or 32bit transfer
|
||||||
*/
|
*/
|
||||||
if (bits_per_word <= 8 && bits_per_word >= 2) {
|
if (bits_per_word <= 8) {
|
||||||
dspi->get_rx = davinci_spi_rx_buf_u8;
|
dspi->get_rx = davinci_spi_rx_buf_u8;
|
||||||
dspi->get_tx = davinci_spi_tx_buf_u8;
|
dspi->get_tx = davinci_spi_tx_buf_u8;
|
||||||
dspi->bytes_per_word[spi->chip_select] = 1;
|
dspi->bytes_per_word[spi->chip_select] = 1;
|
||||||
} else if (bits_per_word <= 16 && bits_per_word >= 2) {
|
} else {
|
||||||
dspi->get_rx = davinci_spi_rx_buf_u16;
|
dspi->get_rx = davinci_spi_rx_buf_u16;
|
||||||
dspi->get_tx = davinci_spi_tx_buf_u16;
|
dspi->get_tx = davinci_spi_tx_buf_u16;
|
||||||
dspi->bytes_per_word[spi->chip_select] = 2;
|
dspi->bytes_per_word[spi->chip_select] = 2;
|
||||||
} else
|
}
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!hz)
|
if (!hz)
|
||||||
hz = spi->max_speed_hz;
|
hz = spi->max_speed_hz;
|
||||||
|
@ -865,7 +864,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_set_drvdata(&pdev->dev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
dspi = spi_master_get_devdata(master);
|
dspi = spi_master_get_devdata(master);
|
||||||
if (dspi == NULL) {
|
if (dspi == NULL) {
|
||||||
|
@ -933,6 +932,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
||||||
master->dev.of_node = pdev->dev.of_node;
|
master->dev.of_node = pdev->dev.of_node;
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = pdata->num_chipselect;
|
master->num_chipselect = pdata->num_chipselect;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
|
||||||
master->setup = davinci_spi_setup;
|
master->setup = davinci_spi_setup;
|
||||||
|
|
||||||
dspi->bitbang.chipselect = davinci_spi_chipselect;
|
dspi->bitbang.chipselect = davinci_spi_chipselect;
|
||||||
|
@ -1044,7 +1044,7 @@ static int davinci_spi_remove(struct platform_device *pdev)
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct resource *r;
|
struct resource *r;
|
||||||
|
|
||||||
master = dev_get_drvdata(&pdev->dev);
|
master = platform_get_drvdata(pdev);
|
||||||
dspi = spi_master_get_devdata(master);
|
dspi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
spi_bitbang_stop(&dspi->bitbang);
|
spi_bitbang_stop(&dspi->bitbang);
|
||||||
|
|
|
@ -111,8 +111,6 @@ static int dw_spi_mmio_remove(struct platform_device *pdev)
|
||||||
struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
|
struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
|
||||||
struct resource *mem;
|
struct resource *mem;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
clk_disable(dwsmmio->clk);
|
clk_disable(dwsmmio->clk);
|
||||||
clk_put(dwsmmio->clk);
|
clk_put(dwsmmio->clk);
|
||||||
dwsmmio->clk = NULL;
|
dwsmmio->clk = NULL;
|
||||||
|
|
|
@ -457,19 +457,7 @@ static void pump_transfers(unsigned long data)
|
||||||
}
|
}
|
||||||
if (transfer->bits_per_word) {
|
if (transfer->bits_per_word) {
|
||||||
bits = transfer->bits_per_word;
|
bits = transfer->bits_per_word;
|
||||||
|
|
||||||
switch (bits) {
|
|
||||||
case 8:
|
|
||||||
case 16:
|
|
||||||
dws->n_bytes = dws->dma_width = bits >> 3;
|
dws->n_bytes = dws->dma_width = bits >> 3;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printk(KERN_ERR "MRST SPI0: unsupported bits:"
|
|
||||||
"%db\n", bits);
|
|
||||||
message->status = -EIO;
|
|
||||||
goto early_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
cr0 = (bits - 1)
|
cr0 = (bits - 1)
|
||||||
| (chip->type << SPI_FRF_OFFSET)
|
| (chip->type << SPI_FRF_OFFSET)
|
||||||
| (spi->mode << SPI_MODE_OFFSET)
|
| (spi->mode << SPI_MODE_OFFSET)
|
||||||
|
@ -629,9 +617,6 @@ 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;
|
||||||
|
|
||||||
if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Only alloc on first setup */
|
/* Only alloc on first setup */
|
||||||
chip = spi_get_ctldata(spi);
|
chip = spi_get_ctldata(spi);
|
||||||
if (!chip) {
|
if (!chip) {
|
||||||
|
@ -660,16 +645,12 @@ static int dw_spi_setup(struct spi_device *spi)
|
||||||
chip->enable_dma = chip_info->enable_dma;
|
chip->enable_dma = chip_info->enable_dma;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spi->bits_per_word <= 8) {
|
if (spi->bits_per_word == 8) {
|
||||||
chip->n_bytes = 1;
|
chip->n_bytes = 1;
|
||||||
chip->dma_width = 1;
|
chip->dma_width = 1;
|
||||||
} else if (spi->bits_per_word <= 16) {
|
} else if (spi->bits_per_word == 16) {
|
||||||
chip->n_bytes = 2;
|
chip->n_bytes = 2;
|
||||||
chip->dma_width = 2;
|
chip->dma_width = 2;
|
||||||
} else {
|
|
||||||
/* Never take >16b case for MRST SPIC */
|
|
||||||
dev_err(&spi->dev, "invalid wordsize\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
chip->bits_per_word = spi->bits_per_word;
|
chip->bits_per_word = spi->bits_per_word;
|
||||||
|
|
||||||
|
@ -824,6 +805,7 @@ int dw_spi_add_host(struct dw_spi *dws)
|
||||||
}
|
}
|
||||||
|
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||||
|
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->cleanup = dw_spi_cleanup;
|
||||||
|
|
|
@ -296,12 +296,6 @@ static int ep93xx_spi_setup(struct spi_device *spi)
|
||||||
struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
|
struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
|
||||||
struct ep93xx_spi_chip *chip;
|
struct ep93xx_spi_chip *chip;
|
||||||
|
|
||||||
if (spi->bits_per_word < 4 || spi->bits_per_word > 16) {
|
|
||||||
dev_err(&espi->pdev->dev, "invalid bits per word %d\n",
|
|
||||||
spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
chip = spi_get_ctldata(spi);
|
chip = spi_get_ctldata(spi);
|
||||||
if (!chip) {
|
if (!chip) {
|
||||||
dev_dbg(&espi->pdev->dev, "initial setup for %s\n",
|
dev_dbg(&espi->pdev->dev, "initial setup for %s\n",
|
||||||
|
@ -365,10 +359,6 @@ static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
|
||||||
|
|
||||||
/* first validate each transfer */
|
/* first validate each transfer */
|
||||||
list_for_each_entry(t, &msg->transfers, transfer_list) {
|
list_for_each_entry(t, &msg->transfers, transfer_list) {
|
||||||
if (t->bits_per_word) {
|
|
||||||
if (t->bits_per_word < 4 || t->bits_per_word > 16)
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (t->speed_hz && t->speed_hz < espi->min_rate)
|
if (t->speed_hz && t->speed_hz < espi->min_rate)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -1046,6 +1036,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = info->num_chipselect;
|
master->num_chipselect = info->num_chipselect;
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
|
@ -1104,6 +1095,7 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
|
||||||
espi->wq = create_singlethread_workqueue("ep93xx_spid");
|
espi->wq = create_singlethread_workqueue("ep93xx_spid");
|
||||||
if (!espi->wq) {
|
if (!espi->wq) {
|
||||||
dev_err(&pdev->dev, "unable to create workqueue\n");
|
dev_err(&pdev->dev, "unable to create workqueue\n");
|
||||||
|
error = -ENOMEM;
|
||||||
goto fail_free_dma;
|
goto fail_free_dma;
|
||||||
}
|
}
|
||||||
INIT_WORK(&espi->msg_work, ep93xx_spi_work);
|
INIT_WORK(&espi->msg_work, ep93xx_spi_work);
|
||||||
|
@ -1132,7 +1124,6 @@ fail_put_clock:
|
||||||
clk_put(espi->clk);
|
clk_put(espi->clk);
|
||||||
fail_release_master:
|
fail_release_master:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -1167,7 +1158,6 @@ static int ep93xx_spi_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
ep93xx_spi_release_dma(espi);
|
ep93xx_spi_release_dma(espi);
|
||||||
clk_put(espi->clk);
|
clk_put(espi->clk);
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
spi_unregister_master(master);
|
spi_unregister_master(master);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -144,10 +144,6 @@ static int fsl_espi_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] */
|
|
||||||
if ((bits_per_word < 4) || (bits_per_word > 16))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (!hz)
|
if (!hz)
|
||||||
hz = spi->max_speed_hz;
|
hz = spi->max_speed_hz;
|
||||||
|
|
||||||
|
@ -157,12 +153,10 @@ static int fsl_espi_setup_transfer(struct spi_device *spi,
|
||||||
cs->get_tx = mpc8xxx_spi_tx_buf_u32;
|
cs->get_tx = mpc8xxx_spi_tx_buf_u32;
|
||||||
if (bits_per_word <= 8) {
|
if (bits_per_word <= 8) {
|
||||||
cs->rx_shift = 8 - bits_per_word;
|
cs->rx_shift = 8 - bits_per_word;
|
||||||
} else if (bits_per_word <= 16) {
|
} else {
|
||||||
cs->rx_shift = 16 - bits_per_word;
|
cs->rx_shift = 16 - bits_per_word;
|
||||||
if (spi->mode & SPI_LSB_FIRST)
|
if (spi->mode & SPI_LSB_FIRST)
|
||||||
cs->get_tx = fsl_espi_tx_buf_lsb;
|
cs->get_tx = fsl_espi_tx_buf_lsb;
|
||||||
} else {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mpc8xxx_spi->rx_shift = cs->rx_shift;
|
mpc8xxx_spi->rx_shift = cs->rx_shift;
|
||||||
|
@ -609,6 +603,7 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_probe;
|
goto err_probe;
|
||||||
|
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
|
||||||
master->setup = fsl_espi_setup;
|
master->setup = fsl_espi_setup;
|
||||||
|
|
||||||
mpc8xxx_spi = spi_master_get_devdata(master);
|
mpc8xxx_spi = spi_master_get_devdata(master);
|
||||||
|
|
|
@ -61,7 +61,7 @@ struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata)
|
||||||
return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
|
return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mpc8xxx_spi_work(struct work_struct *work)
|
static void mpc8xxx_spi_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
|
struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
|
||||||
work);
|
work);
|
||||||
|
|
|
@ -853,7 +853,7 @@ err:
|
||||||
|
|
||||||
static int of_fsl_spi_remove(struct platform_device *ofdev)
|
static int of_fsl_spi_remove(struct platform_device *ofdev)
|
||||||
{
|
{
|
||||||
struct spi_master *master = dev_get_drvdata(&ofdev->dev);
|
struct spi_master *master = platform_get_drvdata(ofdev);
|
||||||
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
|
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
|
@ -239,9 +239,6 @@ static int spi_gpio_setup(struct spi_device *spi)
|
||||||
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
|
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
|
||||||
struct device_node *np = spi->master->dev.of_node;
|
struct device_node *np = spi->master->dev.of_node;
|
||||||
|
|
||||||
if (spi->bits_per_word > 32)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (np) {
|
if (np) {
|
||||||
/*
|
/*
|
||||||
* In DT environments, the CS GPIOs have already been
|
* In DT environments, the CS GPIOs have already been
|
||||||
|
@ -446,6 +443,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
|
||||||
if (pdata)
|
if (pdata)
|
||||||
spi_gpio->pdata = *pdata;
|
spi_gpio->pdata = *pdata;
|
||||||
|
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
|
||||||
master->flags = master_flags;
|
master->flags = master_flags;
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = SPI_N_CHIPSEL;
|
master->num_chipselect = SPI_N_CHIPSEL;
|
||||||
|
@ -514,8 +512,6 @@ static int spi_gpio_remove(struct platform_device *pdev)
|
||||||
status = spi_bitbang_stop(&spi_gpio->bitbang);
|
status = spi_bitbang_stop(&spi_gpio->bitbang);
|
||||||
spi_master_put(spi_gpio->bitbang.master);
|
spi_master_put(spi_gpio->bitbang.master);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
|
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
|
||||||
gpio_free(SPI_MISO_GPIO);
|
gpio_free(SPI_MISO_GPIO);
|
||||||
if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
|
if (SPI_MOSI_GPIO != SPI_GPIO_NO_MOSI)
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
|
||||||
|
|
||||||
#include <linux/platform_data/spi-imx.h>
|
#include <linux/platform_data/spi-imx.h>
|
||||||
|
|
||||||
|
@ -698,11 +697,10 @@ static int spi_imx_setupxfer(struct spi_device *spi,
|
||||||
} else if (config.bpw <= 16) {
|
} else if (config.bpw <= 16) {
|
||||||
spi_imx->rx = spi_imx_buf_rx_u16;
|
spi_imx->rx = spi_imx_buf_rx_u16;
|
||||||
spi_imx->tx = spi_imx_buf_tx_u16;
|
spi_imx->tx = spi_imx_buf_tx_u16;
|
||||||
} else if (config.bpw <= 32) {
|
} else {
|
||||||
spi_imx->rx = spi_imx_buf_rx_u32;
|
spi_imx->rx = spi_imx_buf_rx_u32;
|
||||||
spi_imx->tx = spi_imx_buf_tx_u32;
|
spi_imx->tx = spi_imx_buf_tx_u32;
|
||||||
} else
|
}
|
||||||
BUG();
|
|
||||||
|
|
||||||
spi_imx->devtype_data->config(spi_imx, &config);
|
spi_imx->devtype_data->config(spi_imx, &config);
|
||||||
|
|
||||||
|
@ -760,7 +758,6 @@ static int spi_imx_probe(struct platform_device *pdev)
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct spi_imx_data *spi_imx;
|
struct spi_imx_data *spi_imx;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct pinctrl *pinctrl;
|
|
||||||
int i, ret, num_cs;
|
int i, ret, num_cs;
|
||||||
|
|
||||||
if (!np && !mxc_platform_info) {
|
if (!np && !mxc_platform_info) {
|
||||||
|
@ -783,6 +780,7 @@ static int spi_imx_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
platform_set_drvdata(pdev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = num_cs;
|
master->num_chipselect = num_cs;
|
||||||
|
|
||||||
|
@ -848,12 +846,6 @@ static int spi_imx_probe(struct platform_device *pdev)
|
||||||
goto out_iounmap;
|
goto out_iounmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
|
||||||
if (IS_ERR(pinctrl)) {
|
|
||||||
ret = PTR_ERR(pinctrl);
|
|
||||||
goto out_free_irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
||||||
if (IS_ERR(spi_imx->clk_ipg)) {
|
if (IS_ERR(spi_imx->clk_ipg)) {
|
||||||
ret = PTR_ERR(spi_imx->clk_ipg);
|
ret = PTR_ERR(spi_imx->clk_ipg);
|
||||||
|
@ -902,7 +894,6 @@ out_gpio_free:
|
||||||
}
|
}
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
kfree(master);
|
kfree(master);
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -929,8 +920,6 @@ static int spi_imx_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
release_mem_region(res->start, resource_size(res));
|
release_mem_region(res->start, resource_size(res));
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/workqueue.h>
|
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
@ -33,24 +32,15 @@
|
||||||
|
|
||||||
struct mpc512x_psc_spi {
|
struct mpc512x_psc_spi {
|
||||||
void (*cs_control)(struct spi_device *spi, bool on);
|
void (*cs_control)(struct spi_device *spi, bool on);
|
||||||
u32 sysclk;
|
|
||||||
|
|
||||||
/* driver internal data */
|
/* driver internal data */
|
||||||
struct mpc52xx_psc __iomem *psc;
|
struct mpc52xx_psc __iomem *psc;
|
||||||
struct mpc512x_psc_fifo __iomem *fifo;
|
struct mpc512x_psc_fifo __iomem *fifo;
|
||||||
unsigned int irq;
|
unsigned int irq;
|
||||||
u8 bits_per_word;
|
u8 bits_per_word;
|
||||||
u8 busy;
|
|
||||||
u32 mclk;
|
u32 mclk;
|
||||||
u8 eofbyte;
|
|
||||||
|
|
||||||
struct workqueue_struct *workqueue;
|
struct completion txisrdone;
|
||||||
struct work_struct work;
|
|
||||||
|
|
||||||
struct list_head queue;
|
|
||||||
spinlock_t lock; /* Message queue lock */
|
|
||||||
|
|
||||||
struct completion done;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* controller state */
|
/* controller state */
|
||||||
|
@ -136,99 +126,149 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
|
||||||
struct spi_transfer *t)
|
struct spi_transfer *t)
|
||||||
{
|
{
|
||||||
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
|
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
|
||||||
struct mpc52xx_psc __iomem *psc = mps->psc;
|
|
||||||
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
|
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
|
||||||
size_t len = t->len;
|
size_t tx_len = t->len;
|
||||||
|
size_t rx_len = t->len;
|
||||||
u8 *tx_buf = (u8 *)t->tx_buf;
|
u8 *tx_buf = (u8 *)t->tx_buf;
|
||||||
u8 *rx_buf = (u8 *)t->rx_buf;
|
u8 *rx_buf = (u8 *)t->rx_buf;
|
||||||
|
|
||||||
if (!tx_buf && !rx_buf && t->len)
|
if (!tx_buf && !rx_buf && t->len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Zero MR2 */
|
while (rx_len || tx_len) {
|
||||||
in_8(&psc->mode);
|
size_t txcount;
|
||||||
out_8(&psc->mode, 0x0);
|
|
||||||
|
|
||||||
/* enable transmiter/receiver */
|
|
||||||
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
|
|
||||||
|
|
||||||
while (len) {
|
|
||||||
int count;
|
|
||||||
int i;
|
|
||||||
u8 data;
|
u8 data;
|
||||||
size_t fifosz;
|
size_t fifosz;
|
||||||
int rxcount;
|
size_t rxcount;
|
||||||
|
int rxtries;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The number of bytes that can be sent at a time
|
* send the TX bytes in as large a chunk as possible
|
||||||
* depends on the fifo size.
|
* but neither exceed the TX nor the RX FIFOs
|
||||||
*/
|
*/
|
||||||
fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz));
|
fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz));
|
||||||
count = min(fifosz, len);
|
txcount = min(fifosz, tx_len);
|
||||||
|
fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->rxsz));
|
||||||
|
fifosz -= in_be32(&fifo->rxcnt) + 1;
|
||||||
|
txcount = min(fifosz, txcount);
|
||||||
|
if (txcount) {
|
||||||
|
|
||||||
for (i = count; i > 0; i--) {
|
/* fill the TX FIFO */
|
||||||
|
while (txcount-- > 0) {
|
||||||
data = tx_buf ? *tx_buf++ : 0;
|
data = tx_buf ? *tx_buf++ : 0;
|
||||||
if (len == EOFBYTE && t->cs_change)
|
if (tx_len == EOFBYTE && t->cs_change)
|
||||||
setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF);
|
setbits32(&fifo->txcmd,
|
||||||
|
MPC512x_PSC_FIFO_EOF);
|
||||||
out_8(&fifo->txdata_8, data);
|
out_8(&fifo->txdata_8, data);
|
||||||
len--;
|
tx_len--;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_COMPLETION(mps->done);
|
/* have the ISR trigger when the TX FIFO is empty */
|
||||||
|
INIT_COMPLETION(mps->txisrdone);
|
||||||
/* interrupt on tx fifo empty */
|
|
||||||
out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
|
out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
|
||||||
out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
|
out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
|
||||||
|
wait_for_completion(&mps->txisrdone);
|
||||||
wait_for_completion(&mps->done);
|
|
||||||
|
|
||||||
mdelay(1);
|
|
||||||
|
|
||||||
/* rx fifo should have count bytes in it */
|
|
||||||
rxcount = in_be32(&fifo->rxcnt);
|
|
||||||
if (rxcount != count)
|
|
||||||
mdelay(1);
|
|
||||||
|
|
||||||
rxcount = in_be32(&fifo->rxcnt);
|
|
||||||
if (rxcount != count) {
|
|
||||||
dev_warn(&spi->dev, "expected %d bytes in rx fifo "
|
|
||||||
"but got %d\n", count, rxcount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rxcount = min(rxcount, count);
|
/*
|
||||||
for (i = rxcount; i > 0; i--) {
|
* consume as much RX data as the FIFO holds, while we
|
||||||
|
* iterate over the transfer's TX data length
|
||||||
|
*
|
||||||
|
* only insist in draining all the remaining RX bytes
|
||||||
|
* when the TX bytes were exhausted (that's at the very
|
||||||
|
* end of this transfer, not when still iterating over
|
||||||
|
* the transfer's chunks)
|
||||||
|
*/
|
||||||
|
rxtries = 50;
|
||||||
|
do {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* grab whatever was in the FIFO when we started
|
||||||
|
* looking, don't bother fetching what was added to
|
||||||
|
* the FIFO while we read from it -- we'll return
|
||||||
|
* here eventually and prefer sending out remaining
|
||||||
|
* TX data
|
||||||
|
*/
|
||||||
|
fifosz = in_be32(&fifo->rxcnt);
|
||||||
|
rxcount = min(fifosz, rx_len);
|
||||||
|
while (rxcount-- > 0) {
|
||||||
data = in_8(&fifo->rxdata_8);
|
data = in_8(&fifo->rxdata_8);
|
||||||
if (rx_buf)
|
if (rx_buf)
|
||||||
*rx_buf++ = data;
|
*rx_buf++ = data;
|
||||||
|
rx_len--;
|
||||||
}
|
}
|
||||||
while (in_be32(&fifo->rxcnt)) {
|
|
||||||
|
/*
|
||||||
|
* come back later if there still is TX data to send,
|
||||||
|
* bail out of the RX drain loop if all of the TX data
|
||||||
|
* was sent and all of the RX data was received (i.e.
|
||||||
|
* when the transmission has completed)
|
||||||
|
*/
|
||||||
|
if (tx_len)
|
||||||
|
break;
|
||||||
|
if (!rx_len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TX data transmission has completed while RX data
|
||||||
|
* is still pending -- that's a transient situation
|
||||||
|
* which depends on wire speed and specific
|
||||||
|
* hardware implementation details (buffering) yet
|
||||||
|
* should resolve very quickly
|
||||||
|
*
|
||||||
|
* just yield for a moment to not hog the CPU for
|
||||||
|
* too long when running SPI at low speed
|
||||||
|
*
|
||||||
|
* the timeout range is rather arbitrary and tries
|
||||||
|
* to balance throughput against system load; the
|
||||||
|
* chosen values result in a minimal timeout of 50
|
||||||
|
* times 10us and thus work at speeds as low as
|
||||||
|
* some 20kbps, while the maximum timeout at the
|
||||||
|
* transfer's end could be 5ms _if_ nothing else
|
||||||
|
* ticks in the system _and_ RX data still wasn't
|
||||||
|
* received, which only occurs in situations that
|
||||||
|
* are exceptional; removing the unpredictability
|
||||||
|
* of the timeout either decreases throughput
|
||||||
|
* (longer timeouts), or puts more load on the
|
||||||
|
* system (fixed short timeouts) or requires the
|
||||||
|
* use of a timeout API instead of a counter and an
|
||||||
|
* unknown inner delay
|
||||||
|
*/
|
||||||
|
usleep_range(10, 100);
|
||||||
|
|
||||||
|
} while (--rxtries > 0);
|
||||||
|
if (!tx_len && rx_len && !rxtries) {
|
||||||
|
/*
|
||||||
|
* not enough RX bytes even after several retries
|
||||||
|
* and the resulting rather long timeout?
|
||||||
|
*/
|
||||||
|
rxcount = in_be32(&fifo->rxcnt);
|
||||||
|
dev_warn(&spi->dev,
|
||||||
|
"short xfer, missing %zd RX bytes, FIFO level %zd\n",
|
||||||
|
rx_len, rxcount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* drain and drop RX data which "should not be there" in
|
||||||
|
* the first place, for undisturbed transmission this turns
|
||||||
|
* into a NOP (except for the FIFO level fetch)
|
||||||
|
*/
|
||||||
|
if (!tx_len && !rx_len) {
|
||||||
|
while (in_be32(&fifo->rxcnt))
|
||||||
in_8(&fifo->rxdata_8);
|
in_8(&fifo->rxdata_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
/* disable transmiter/receiver and fifo interrupt */
|
|
||||||
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
|
|
||||||
out_be32(&fifo->tximr, 0);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mpc512x_psc_spi_work(struct work_struct *work)
|
static int mpc512x_psc_spi_msg_xfer(struct spi_master *master,
|
||||||
|
struct spi_message *m)
|
||||||
{
|
{
|
||||||
struct mpc512x_psc_spi *mps = container_of(work,
|
|
||||||
struct mpc512x_psc_spi,
|
|
||||||
work);
|
|
||||||
|
|
||||||
spin_lock_irq(&mps->lock);
|
|
||||||
mps->busy = 1;
|
|
||||||
while (!list_empty(&mps->queue)) {
|
|
||||||
struct spi_message *m;
|
|
||||||
struct spi_device *spi;
|
struct spi_device *spi;
|
||||||
struct spi_transfer *t = NULL;
|
|
||||||
unsigned cs_change;
|
unsigned cs_change;
|
||||||
int status;
|
int status;
|
||||||
|
struct spi_transfer *t;
|
||||||
m = container_of(mps->queue.next, struct spi_message, queue);
|
|
||||||
list_del_init(&m->queue);
|
|
||||||
spin_unlock_irq(&mps->lock);
|
|
||||||
|
|
||||||
spi = m->spi;
|
spi = m->spi;
|
||||||
cs_change = 1;
|
cs_change = 1;
|
||||||
|
@ -264,17 +304,45 @@ static void mpc512x_psc_spi_work(struct work_struct *work)
|
||||||
|
|
||||||
mpc512x_psc_spi_transfer_setup(spi, NULL);
|
mpc512x_psc_spi_transfer_setup(spi, NULL);
|
||||||
|
|
||||||
spin_lock_irq(&mps->lock);
|
spi_finalize_current_message(master);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
mps->busy = 0;
|
|
||||||
spin_unlock_irq(&mps->lock);
|
static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
|
||||||
|
{
|
||||||
|
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
|
||||||
|
struct mpc52xx_psc __iomem *psc = mps->psc;
|
||||||
|
|
||||||
|
dev_dbg(&master->dev, "%s()\n", __func__);
|
||||||
|
|
||||||
|
/* Zero MR2 */
|
||||||
|
in_8(&psc->mode);
|
||||||
|
out_8(&psc->mode, 0x0);
|
||||||
|
|
||||||
|
/* enable transmitter/receiver */
|
||||||
|
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master)
|
||||||
|
{
|
||||||
|
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
|
||||||
|
struct mpc52xx_psc __iomem *psc = mps->psc;
|
||||||
|
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
|
||||||
|
|
||||||
|
dev_dbg(&master->dev, "%s()\n", __func__);
|
||||||
|
|
||||||
|
/* disable transmitter/receiver and fifo interrupt */
|
||||||
|
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
|
||||||
|
out_be32(&fifo->tximr, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mpc512x_psc_spi_setup(struct spi_device *spi)
|
static int mpc512x_psc_spi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
|
|
||||||
struct mpc512x_psc_spi_cs *cs = spi->controller_state;
|
struct mpc512x_psc_spi_cs *cs = spi->controller_state;
|
||||||
unsigned long flags;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (spi->bits_per_word % 8)
|
if (spi->bits_per_word % 8)
|
||||||
|
@ -303,28 +371,6 @@ static int mpc512x_psc_spi_setup(struct spi_device *spi)
|
||||||
cs->bits_per_word = spi->bits_per_word;
|
cs->bits_per_word = spi->bits_per_word;
|
||||||
cs->speed_hz = spi->max_speed_hz;
|
cs->speed_hz = spi->max_speed_hz;
|
||||||
|
|
||||||
spin_lock_irqsave(&mps->lock, flags);
|
|
||||||
if (!mps->busy)
|
|
||||||
mpc512x_psc_spi_deactivate_cs(spi);
|
|
||||||
spin_unlock_irqrestore(&mps->lock, flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mpc512x_psc_spi_transfer(struct spi_device *spi,
|
|
||||||
struct spi_message *m)
|
|
||||||
{
|
|
||||||
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
m->actual_length = 0;
|
|
||||||
m->status = -EINPROGRESS;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&mps->lock, flags);
|
|
||||||
list_add_tail(&m->queue, &mps->queue);
|
|
||||||
queue_work(mps->workqueue, &mps->work);
|
|
||||||
spin_unlock_irqrestore(&mps->lock, flags);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,12 +453,12 @@ static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
|
||||||
struct mpc512x_psc_spi *mps = (struct mpc512x_psc_spi *)dev_id;
|
struct mpc512x_psc_spi *mps = (struct mpc512x_psc_spi *)dev_id;
|
||||||
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
|
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
|
||||||
|
|
||||||
/* clear interrupt and wake up the work queue */
|
/* clear interrupt and wake up the rx/tx routine */
|
||||||
if (in_be32(&fifo->txisr) &
|
if (in_be32(&fifo->txisr) &
|
||||||
in_be32(&fifo->tximr) & MPC512x_PSC_FIFO_EMPTY) {
|
in_be32(&fifo->tximr) & MPC512x_PSC_FIFO_EMPTY) {
|
||||||
out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
|
out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
|
||||||
out_be32(&fifo->tximr, 0);
|
out_be32(&fifo->tximr, 0);
|
||||||
complete(&mps->done);
|
complete(&mps->txisrdone);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
@ -444,18 +490,18 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
||||||
|
|
||||||
if (pdata == NULL) {
|
if (pdata == NULL) {
|
||||||
mps->cs_control = mpc512x_spi_cs_control;
|
mps->cs_control = mpc512x_spi_cs_control;
|
||||||
mps->sysclk = 0;
|
|
||||||
master->bus_num = bus_num;
|
master->bus_num = bus_num;
|
||||||
} else {
|
} else {
|
||||||
mps->cs_control = pdata->cs_control;
|
mps->cs_control = pdata->cs_control;
|
||||||
mps->sysclk = pdata->sysclk;
|
|
||||||
master->bus_num = pdata->bus_num;
|
master->bus_num = pdata->bus_num;
|
||||||
master->num_chipselect = pdata->max_chipselect;
|
master->num_chipselect = pdata->max_chipselect;
|
||||||
}
|
}
|
||||||
|
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
|
||||||
master->setup = mpc512x_psc_spi_setup;
|
master->setup = mpc512x_psc_spi_setup;
|
||||||
master->transfer = mpc512x_psc_spi_transfer;
|
master->prepare_transfer_hardware = mpc512x_psc_spi_prep_xfer_hw;
|
||||||
|
master->transfer_one_message = mpc512x_psc_spi_msg_xfer;
|
||||||
|
master->unprepare_transfer_hardware = mpc512x_psc_spi_unprep_xfer_hw;
|
||||||
master->cleanup = mpc512x_psc_spi_cleanup;
|
master->cleanup = mpc512x_psc_spi_cleanup;
|
||||||
master->dev.of_node = dev->of_node;
|
master->dev.of_node = dev->of_node;
|
||||||
|
|
||||||
|
@ -473,31 +519,18 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
|
||||||
"mpc512x-psc-spi", mps);
|
"mpc512x-psc-spi", mps);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto free_master;
|
goto free_master;
|
||||||
|
init_completion(&mps->txisrdone);
|
||||||
|
|
||||||
ret = mpc512x_psc_spi_port_config(master, mps);
|
ret = mpc512x_psc_spi_port_config(master, mps);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto free_irq;
|
goto free_irq;
|
||||||
|
|
||||||
spin_lock_init(&mps->lock);
|
|
||||||
init_completion(&mps->done);
|
|
||||||
INIT_WORK(&mps->work, mpc512x_psc_spi_work);
|
|
||||||
INIT_LIST_HEAD(&mps->queue);
|
|
||||||
|
|
||||||
mps->workqueue =
|
|
||||||
create_singlethread_workqueue(dev_name(master->dev.parent));
|
|
||||||
if (mps->workqueue == NULL) {
|
|
||||||
ret = -EBUSY;
|
|
||||||
goto free_irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = spi_register_master(master);
|
ret = spi_register_master(master);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto unreg_master;
|
goto free_irq;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
unreg_master:
|
|
||||||
destroy_workqueue(mps->workqueue);
|
|
||||||
free_irq:
|
free_irq:
|
||||||
free_irq(mps->irq, mps);
|
free_irq(mps->irq, mps);
|
||||||
free_master:
|
free_master:
|
||||||
|
@ -513,8 +546,6 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
|
||||||
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
|
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
|
||||||
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
|
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
|
||||||
|
|
||||||
flush_workqueue(mps->workqueue);
|
|
||||||
destroy_workqueue(mps->workqueue);
|
|
||||||
spi_unregister_master(master);
|
spi_unregister_master(master);
|
||||||
free_irq(mps->irq, mps);
|
free_irq(mps->irq, mps);
|
||||||
if (mps->psc)
|
if (mps->psc)
|
||||||
|
|
|
@ -481,7 +481,7 @@ static int mpc52xx_psc_spi_of_probe(struct platform_device *op)
|
||||||
|
|
||||||
static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
|
static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
|
||||||
{
|
{
|
||||||
struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
|
struct spi_master *master = spi_master_get(platform_get_drvdata(op));
|
||||||
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
|
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
|
||||||
|
|
||||||
flush_workqueue(mps->workqueue);
|
flush_workqueue(mps->workqueue);
|
||||||
|
|
|
@ -438,7 +438,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
||||||
master->dev.of_node = op->dev.of_node;
|
master->dev.of_node = op->dev.of_node;
|
||||||
|
|
||||||
dev_set_drvdata(&op->dev, master);
|
platform_set_drvdata(op, master);
|
||||||
|
|
||||||
ms = spi_master_get_devdata(master);
|
ms = spi_master_get_devdata(master);
|
||||||
ms->master = master;
|
ms->master = master;
|
||||||
|
@ -529,7 +529,7 @@ static int mpc52xx_spi_probe(struct platform_device *op)
|
||||||
|
|
||||||
static int mpc52xx_spi_remove(struct platform_device *op)
|
static int mpc52xx_spi_remove(struct platform_device *op)
|
||||||
{
|
{
|
||||||
struct spi_master *master = spi_master_get(dev_get_drvdata(&op->dev));
|
struct spi_master *master = spi_master_get(platform_get_drvdata(op));
|
||||||
struct mpc52xx_spi *ms = spi_master_get_devdata(master);
|
struct mpc52xx_spi *ms = spi_master_get_devdata(master);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,6 @@
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
|
||||||
#include <linux/stmp_device.h>
|
#include <linux/stmp_device.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/mxs-spi.h>
|
#include <linux/spi/mxs-spi.h>
|
||||||
|
@ -75,12 +74,6 @@ static int mxs_spi_setup_transfer(struct spi_device *dev,
|
||||||
if (t && t->bits_per_word)
|
if (t && t->bits_per_word)
|
||||||
bits_per_word = t->bits_per_word;
|
bits_per_word = t->bits_per_word;
|
||||||
|
|
||||||
if (bits_per_word != 8) {
|
|
||||||
dev_err(&dev->dev, "%s, unsupported bits_per_word=%d\n",
|
|
||||||
__func__, bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hz = dev->max_speed_hz;
|
hz = dev->max_speed_hz;
|
||||||
if (t && t->speed_hz)
|
if (t && t->speed_hz)
|
||||||
hz = min(hz, t->speed_hz);
|
hz = min(hz, t->speed_hz);
|
||||||
|
@ -506,7 +499,6 @@ static int mxs_spi_probe(struct platform_device *pdev)
|
||||||
struct mxs_spi *spi;
|
struct mxs_spi *spi;
|
||||||
struct mxs_ssp *ssp;
|
struct mxs_ssp *ssp;
|
||||||
struct resource *iores;
|
struct resource *iores;
|
||||||
struct pinctrl *pinctrl;
|
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int devid, clk_freq;
|
int devid, clk_freq;
|
||||||
|
@ -528,10 +520,6 @@ static int mxs_spi_probe(struct platform_device *pdev)
|
||||||
if (IS_ERR(base))
|
if (IS_ERR(base))
|
||||||
return PTR_ERR(base);
|
return PTR_ERR(base);
|
||||||
|
|
||||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
|
||||||
if (IS_ERR(pinctrl))
|
|
||||||
return PTR_ERR(pinctrl);
|
|
||||||
|
|
||||||
clk = devm_clk_get(&pdev->dev, NULL);
|
clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(clk))
|
if (IS_ERR(clk))
|
||||||
return PTR_ERR(clk);
|
return PTR_ERR(clk);
|
||||||
|
@ -548,6 +536,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
master->transfer_one_message = mxs_spi_transfer_one;
|
master->transfer_one_message = mxs_spi_transfer_one;
|
||||||
master->setup = mxs_spi_setup;
|
master->setup = mxs_spi_setup;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||||
master->num_chipselect = 3;
|
master->num_chipselect = 3;
|
||||||
master->dev.of_node = np;
|
master->dev.of_node = np;
|
||||||
|
|
|
@ -174,17 +174,6 @@ static void nuc900_spi_gobusy(struct nuc900_spi *hw)
|
||||||
spin_unlock_irqrestore(&hw->lock, flags);
|
spin_unlock_irqrestore(&hw->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nuc900_spi_setupxfer(struct spi_device *spi,
|
|
||||||
struct spi_transfer *t)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int nuc900_spi_setup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
|
static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
|
||||||
{
|
{
|
||||||
return hw->tx ? hw->tx[count] : 0;
|
return hw->tx ? hw->tx[count] : 0;
|
||||||
|
@ -377,10 +366,8 @@ static int nuc900_spi_probe(struct platform_device *pdev)
|
||||||
master->num_chipselect = hw->pdata->num_cs;
|
master->num_chipselect = hw->pdata->num_cs;
|
||||||
master->bus_num = hw->pdata->bus_num;
|
master->bus_num = hw->pdata->bus_num;
|
||||||
hw->bitbang.master = hw->master;
|
hw->bitbang.master = hw->master;
|
||||||
hw->bitbang.setup_transfer = nuc900_spi_setupxfer;
|
|
||||||
hw->bitbang.chipselect = nuc900_spi_chipsel;
|
hw->bitbang.chipselect = nuc900_spi_chipsel;
|
||||||
hw->bitbang.txrx_bufs = nuc900_spi_txrx;
|
hw->bitbang.txrx_bufs = nuc900_spi_txrx;
|
||||||
hw->bitbang.master->setup = nuc900_spi_setup;
|
|
||||||
|
|
||||||
hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
if (hw->res == NULL) {
|
if (hw->res == NULL) {
|
||||||
|
@ -459,8 +446,6 @@ static int nuc900_spi_remove(struct platform_device *dev)
|
||||||
|
|
||||||
free_irq(hw->irq, hw);
|
free_irq(hw->irq, hw);
|
||||||
|
|
||||||
platform_set_drvdata(dev, NULL);
|
|
||||||
|
|
||||||
spi_bitbang_stop(&hw->bitbang);
|
spi_bitbang_stop(&hw->bitbang);
|
||||||
|
|
||||||
clk_disable(hw->clk);
|
clk_disable(hw->clk);
|
||||||
|
|
|
@ -368,7 +368,6 @@ exit_gpio:
|
||||||
exit_busy:
|
exit_busy:
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
exit:
|
exit:
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -382,7 +381,6 @@ static int tiny_spi_remove(struct platform_device *pdev)
|
||||||
spi_bitbang_stop(&hw->bitbang);
|
spi_bitbang_stop(&hw->bitbang);
|
||||||
for (i = 0; i < hw->gpio_cs_count; i++)
|
for (i = 0; i < hw->gpio_cs_count; i++)
|
||||||
gpio_free(hw->gpio_cs[i]);
|
gpio_free(hw->gpio_cs[i]);
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -298,12 +298,6 @@ static int omap1_spi100k_setup(struct spi_device *spi)
|
||||||
struct omap1_spi100k *spi100k;
|
struct omap1_spi100k *spi100k;
|
||||||
struct omap1_spi100k_cs *cs = spi->controller_state;
|
struct omap1_spi100k_cs *cs = spi->controller_state;
|
||||||
|
|
||||||
if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
|
|
||||||
dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
|
|
||||||
spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
spi100k = spi_master_get_devdata(spi->master);
|
spi100k = spi_master_get_devdata(spi->master);
|
||||||
|
|
||||||
if (!cs) {
|
if (!cs) {
|
||||||
|
@ -451,10 +445,7 @@ static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m)
|
||||||
unsigned len = t->len;
|
unsigned len = t->len;
|
||||||
|
|
||||||
if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
|
if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ
|
||||||
|| (len && !(rx_buf || tx_buf))
|
|| (len && !(rx_buf || tx_buf))) {
|
||||||
|| (t->bits_per_word &&
|
|
||||||
( t->bits_per_word < 4
|
|
||||||
|| t->bits_per_word > 32))) {
|
|
||||||
dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
|
dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
|
||||||
t->speed_hz,
|
t->speed_hz,
|
||||||
len,
|
len,
|
||||||
|
@ -509,8 +500,9 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
|
||||||
master->cleanup = NULL;
|
master->cleanup = NULL;
|
||||||
master->num_chipselect = 2;
|
master->num_chipselect = 2;
|
||||||
master->mode_bits = MODEBITS;
|
master->mode_bits = MODEBITS;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||||
|
|
||||||
dev_set_drvdata(&pdev->dev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
spi100k = spi_master_get_devdata(master);
|
spi100k = spi_master_get_devdata(master);
|
||||||
spi100k->master = master;
|
spi100k->master = master;
|
||||||
|
@ -569,7 +561,7 @@ static int omap1_spi100k_remove(struct platform_device *pdev)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
master = dev_get_drvdata(&pdev->dev);
|
master = platform_get_drvdata(pdev);
|
||||||
spi100k = spi_master_get_devdata(master);
|
spi100k = spi_master_get_devdata(master);
|
||||||
|
|
||||||
spin_lock_irqsave(&spi100k->lock, flags);
|
spin_lock_irqsave(&spi100k->lock, flags);
|
||||||
|
|
|
@ -495,7 +495,7 @@ static int uwire_probe(struct platform_device *pdev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_set_drvdata(&pdev->dev, uwire);
|
platform_set_drvdata(pdev, uwire);
|
||||||
|
|
||||||
uwire->ck = clk_get(&pdev->dev, "fck");
|
uwire->ck = clk_get(&pdev->dev, "fck");
|
||||||
if (IS_ERR(uwire->ck)) {
|
if (IS_ERR(uwire->ck)) {
|
||||||
|
@ -538,7 +538,7 @@ static int uwire_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
static int uwire_remove(struct platform_device *pdev)
|
static int uwire_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct uwire_spi *uwire = dev_get_drvdata(&pdev->dev);
|
struct uwire_spi *uwire = platform_get_drvdata(pdev);
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
// FIXME remove all child devices, somewhere ...
|
// FIXME remove all child devices, somewhere ...
|
||||||
|
|
|
@ -38,13 +38,15 @@
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/gcd.h>
|
||||||
|
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
|
|
||||||
#include <linux/platform_data/spi-omap2-mcspi.h>
|
#include <linux/platform_data/spi-omap2-mcspi.h>
|
||||||
|
|
||||||
#define OMAP2_MCSPI_MAX_FREQ 48000000
|
#define OMAP2_MCSPI_MAX_FREQ 48000000
|
||||||
|
#define OMAP2_MCSPI_MAX_FIFODEPTH 64
|
||||||
|
#define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF
|
||||||
#define SPI_AUTOSUSPEND_TIMEOUT 2000
|
#define SPI_AUTOSUSPEND_TIMEOUT 2000
|
||||||
|
|
||||||
#define OMAP2_MCSPI_REVISION 0x00
|
#define OMAP2_MCSPI_REVISION 0x00
|
||||||
|
@ -54,6 +56,7 @@
|
||||||
#define OMAP2_MCSPI_WAKEUPENABLE 0x20
|
#define OMAP2_MCSPI_WAKEUPENABLE 0x20
|
||||||
#define OMAP2_MCSPI_SYST 0x24
|
#define OMAP2_MCSPI_SYST 0x24
|
||||||
#define OMAP2_MCSPI_MODULCTRL 0x28
|
#define OMAP2_MCSPI_MODULCTRL 0x28
|
||||||
|
#define OMAP2_MCSPI_XFERLEVEL 0x7c
|
||||||
|
|
||||||
/* per-channel banks, 0x14 bytes each, first is: */
|
/* per-channel banks, 0x14 bytes each, first is: */
|
||||||
#define OMAP2_MCSPI_CHCONF0 0x2c
|
#define OMAP2_MCSPI_CHCONF0 0x2c
|
||||||
|
@ -63,6 +66,7 @@
|
||||||
#define OMAP2_MCSPI_RX0 0x3c
|
#define OMAP2_MCSPI_RX0 0x3c
|
||||||
|
|
||||||
/* per-register bitmasks: */
|
/* per-register bitmasks: */
|
||||||
|
#define OMAP2_MCSPI_IRQSTATUS_EOW BIT(17)
|
||||||
|
|
||||||
#define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0)
|
#define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0)
|
||||||
#define OMAP2_MCSPI_MODULCTRL_MS BIT(2)
|
#define OMAP2_MCSPI_MODULCTRL_MS BIT(2)
|
||||||
|
@ -83,10 +87,13 @@
|
||||||
#define OMAP2_MCSPI_CHCONF_IS BIT(18)
|
#define OMAP2_MCSPI_CHCONF_IS BIT(18)
|
||||||
#define OMAP2_MCSPI_CHCONF_TURBO BIT(19)
|
#define OMAP2_MCSPI_CHCONF_TURBO BIT(19)
|
||||||
#define OMAP2_MCSPI_CHCONF_FORCE BIT(20)
|
#define OMAP2_MCSPI_CHCONF_FORCE BIT(20)
|
||||||
|
#define OMAP2_MCSPI_CHCONF_FFET BIT(27)
|
||||||
|
#define OMAP2_MCSPI_CHCONF_FFER BIT(28)
|
||||||
|
|
||||||
#define OMAP2_MCSPI_CHSTAT_RXS BIT(0)
|
#define OMAP2_MCSPI_CHSTAT_RXS BIT(0)
|
||||||
#define OMAP2_MCSPI_CHSTAT_TXS BIT(1)
|
#define OMAP2_MCSPI_CHSTAT_TXS BIT(1)
|
||||||
#define OMAP2_MCSPI_CHSTAT_EOT BIT(2)
|
#define OMAP2_MCSPI_CHSTAT_EOT BIT(2)
|
||||||
|
#define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3)
|
||||||
|
|
||||||
#define OMAP2_MCSPI_CHCTRL_EN BIT(0)
|
#define OMAP2_MCSPI_CHCTRL_EN BIT(0)
|
||||||
|
|
||||||
|
@ -102,6 +109,9 @@ struct omap2_mcspi_dma {
|
||||||
|
|
||||||
struct completion dma_tx_completion;
|
struct completion dma_tx_completion;
|
||||||
struct completion dma_rx_completion;
|
struct completion dma_rx_completion;
|
||||||
|
|
||||||
|
char dma_rx_ch_name[14];
|
||||||
|
char dma_tx_ch_name[14];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
|
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
|
||||||
|
@ -129,6 +139,7 @@ struct omap2_mcspi {
|
||||||
struct omap2_mcspi_dma *dma_channels;
|
struct omap2_mcspi_dma *dma_channels;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct omap2_mcspi_regs ctx;
|
struct omap2_mcspi_regs ctx;
|
||||||
|
int fifo_depth;
|
||||||
unsigned int pin_dir:1;
|
unsigned int pin_dir:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -187,6 +198,16 @@ static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
|
||||||
mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
|
mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int mcspi_bytes_per_word(int word_len)
|
||||||
|
{
|
||||||
|
if (word_len <= 8)
|
||||||
|
return 1;
|
||||||
|
else if (word_len <= 16)
|
||||||
|
return 2;
|
||||||
|
else /* word_len <= 32 */
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
|
static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
|
||||||
int is_read, int enable)
|
int is_read, int enable)
|
||||||
{
|
{
|
||||||
|
@ -248,6 +269,58 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master)
|
||||||
ctx->modulctrl = l;
|
ctx->modulctrl = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void omap2_mcspi_set_fifo(const struct spi_device *spi,
|
||||||
|
struct spi_transfer *t, int enable)
|
||||||
|
{
|
||||||
|
struct spi_master *master = spi->master;
|
||||||
|
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||||
|
struct omap2_mcspi *mcspi;
|
||||||
|
unsigned int wcnt;
|
||||||
|
int fifo_depth, bytes_per_word;
|
||||||
|
u32 chconf, xferlevel;
|
||||||
|
|
||||||
|
mcspi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
|
chconf = mcspi_cached_chconf0(spi);
|
||||||
|
if (enable) {
|
||||||
|
bytes_per_word = mcspi_bytes_per_word(cs->word_len);
|
||||||
|
if (t->len % bytes_per_word != 0)
|
||||||
|
goto disable_fifo;
|
||||||
|
|
||||||
|
fifo_depth = gcd(t->len, OMAP2_MCSPI_MAX_FIFODEPTH);
|
||||||
|
if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0)
|
||||||
|
goto disable_fifo;
|
||||||
|
|
||||||
|
wcnt = t->len / bytes_per_word;
|
||||||
|
if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
|
||||||
|
goto disable_fifo;
|
||||||
|
|
||||||
|
xferlevel = wcnt << 16;
|
||||||
|
if (t->rx_buf != NULL) {
|
||||||
|
chconf |= OMAP2_MCSPI_CHCONF_FFER;
|
||||||
|
xferlevel |= (fifo_depth - 1) << 8;
|
||||||
|
} else {
|
||||||
|
chconf |= OMAP2_MCSPI_CHCONF_FFET;
|
||||||
|
xferlevel |= fifo_depth - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);
|
||||||
|
mcspi_write_chconf0(spi, chconf);
|
||||||
|
mcspi->fifo_depth = fifo_depth;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_fifo:
|
||||||
|
if (t->rx_buf != NULL)
|
||||||
|
chconf &= ~OMAP2_MCSPI_CHCONF_FFER;
|
||||||
|
else
|
||||||
|
chconf &= ~OMAP2_MCSPI_CHCONF_FFET;
|
||||||
|
|
||||||
|
mcspi_write_chconf0(spi, chconf);
|
||||||
|
mcspi->fifo_depth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
|
static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
|
||||||
{
|
{
|
||||||
struct spi_master *spi_cntrl = mcspi->master;
|
struct spi_master *spi_cntrl = mcspi->master;
|
||||||
|
@ -364,7 +437,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
{
|
{
|
||||||
struct omap2_mcspi *mcspi;
|
struct omap2_mcspi *mcspi;
|
||||||
struct omap2_mcspi_dma *mcspi_dma;
|
struct omap2_mcspi_dma *mcspi_dma;
|
||||||
unsigned int count;
|
unsigned int count, dma_count;
|
||||||
u32 l;
|
u32 l;
|
||||||
int elements = 0;
|
int elements = 0;
|
||||||
int word_len, element_count;
|
int word_len, element_count;
|
||||||
|
@ -372,6 +445,11 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
mcspi = spi_master_get_devdata(spi->master);
|
mcspi = spi_master_get_devdata(spi->master);
|
||||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||||
count = xfer->len;
|
count = xfer->len;
|
||||||
|
dma_count = xfer->len;
|
||||||
|
|
||||||
|
if (mcspi->fifo_depth == 0)
|
||||||
|
dma_count -= es;
|
||||||
|
|
||||||
word_len = cs->word_len;
|
word_len = cs->word_len;
|
||||||
l = mcspi_cached_chconf0(spi);
|
l = mcspi_cached_chconf0(spi);
|
||||||
|
|
||||||
|
@ -385,16 +463,15 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
if (mcspi_dma->dma_rx) {
|
if (mcspi_dma->dma_rx) {
|
||||||
struct dma_async_tx_descriptor *tx;
|
struct dma_async_tx_descriptor *tx;
|
||||||
struct scatterlist sg;
|
struct scatterlist sg;
|
||||||
size_t len = xfer->len - es;
|
|
||||||
|
|
||||||
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
|
dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
|
||||||
|
|
||||||
if (l & OMAP2_MCSPI_CHCONF_TURBO)
|
if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
|
||||||
len -= es;
|
dma_count -= es;
|
||||||
|
|
||||||
sg_init_table(&sg, 1);
|
sg_init_table(&sg, 1);
|
||||||
sg_dma_address(&sg) = xfer->rx_dma;
|
sg_dma_address(&sg) = xfer->rx_dma;
|
||||||
sg_dma_len(&sg) = len;
|
sg_dma_len(&sg) = dma_count;
|
||||||
|
|
||||||
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
|
tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
|
||||||
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
|
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
|
||||||
|
@ -414,6 +491,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
wait_for_completion(&mcspi_dma->dma_rx_completion);
|
wait_for_completion(&mcspi_dma->dma_rx_completion);
|
||||||
dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
|
dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
|
|
||||||
|
if (mcspi->fifo_depth > 0)
|
||||||
|
return count;
|
||||||
|
|
||||||
omap2_mcspi_set_enable(spi, 0);
|
omap2_mcspi_set_enable(spi, 0);
|
||||||
|
|
||||||
elements = element_count - 1;
|
elements = element_count - 1;
|
||||||
|
@ -433,10 +514,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
else /* word_len <= 32 */
|
else /* word_len <= 32 */
|
||||||
((u32 *)xfer->rx_buf)[elements++] = w;
|
((u32 *)xfer->rx_buf)[elements++] = w;
|
||||||
} else {
|
} else {
|
||||||
|
int bytes_per_word = mcspi_bytes_per_word(word_len);
|
||||||
dev_err(&spi->dev, "DMA RX penultimate word empty");
|
dev_err(&spi->dev, "DMA RX penultimate word empty");
|
||||||
count -= (word_len <= 8) ? 2 :
|
count -= (bytes_per_word << 1);
|
||||||
(word_len <= 16) ? 4 :
|
|
||||||
/* word_len <= 32 */ 8;
|
|
||||||
omap2_mcspi_set_enable(spi, 1);
|
omap2_mcspi_set_enable(spi, 1);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@ -454,9 +534,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
|
||||||
((u32 *)xfer->rx_buf)[elements] = w;
|
((u32 *)xfer->rx_buf)[elements] = w;
|
||||||
} else {
|
} else {
|
||||||
dev_err(&spi->dev, "DMA RX last word empty");
|
dev_err(&spi->dev, "DMA RX last word empty");
|
||||||
count -= (word_len <= 8) ? 1 :
|
count -= mcspi_bytes_per_word(word_len);
|
||||||
(word_len <= 16) ? 2 :
|
|
||||||
/* word_len <= 32 */ 4;
|
|
||||||
}
|
}
|
||||||
omap2_mcspi_set_enable(spi, 1);
|
omap2_mcspi_set_enable(spi, 1);
|
||||||
return count;
|
return count;
|
||||||
|
@ -475,7 +553,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
|
||||||
struct dma_slave_config cfg;
|
struct dma_slave_config cfg;
|
||||||
enum dma_slave_buswidth width;
|
enum dma_slave_buswidth width;
|
||||||
unsigned es;
|
unsigned es;
|
||||||
|
u32 burst;
|
||||||
void __iomem *chstat_reg;
|
void __iomem *chstat_reg;
|
||||||
|
void __iomem *irqstat_reg;
|
||||||
|
int wait_res;
|
||||||
|
|
||||||
mcspi = spi_master_get_devdata(spi->master);
|
mcspi = spi_master_get_devdata(spi->master);
|
||||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||||
|
@ -493,19 +574,27 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
|
||||||
es = 4;
|
es = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
count = xfer->len;
|
||||||
|
burst = 1;
|
||||||
|
|
||||||
|
if (mcspi->fifo_depth > 0) {
|
||||||
|
if (count > mcspi->fifo_depth)
|
||||||
|
burst = mcspi->fifo_depth / es;
|
||||||
|
else
|
||||||
|
burst = count / es;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&cfg, 0, sizeof(cfg));
|
memset(&cfg, 0, sizeof(cfg));
|
||||||
cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
|
cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
|
||||||
cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
|
cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
|
||||||
cfg.src_addr_width = width;
|
cfg.src_addr_width = width;
|
||||||
cfg.dst_addr_width = width;
|
cfg.dst_addr_width = width;
|
||||||
cfg.src_maxburst = 1;
|
cfg.src_maxburst = burst;
|
||||||
cfg.dst_maxburst = 1;
|
cfg.dst_maxburst = burst;
|
||||||
|
|
||||||
rx = xfer->rx_buf;
|
rx = xfer->rx_buf;
|
||||||
tx = xfer->tx_buf;
|
tx = xfer->tx_buf;
|
||||||
|
|
||||||
count = xfer->len;
|
|
||||||
|
|
||||||
if (tx != NULL)
|
if (tx != NULL)
|
||||||
omap2_mcspi_tx_dma(spi, xfer, cfg);
|
omap2_mcspi_tx_dma(spi, xfer, cfg);
|
||||||
|
|
||||||
|
@ -513,18 +602,38 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
|
||||||
count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
|
count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
|
||||||
|
|
||||||
if (tx != NULL) {
|
if (tx != NULL) {
|
||||||
chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
|
||||||
wait_for_completion(&mcspi_dma->dma_tx_completion);
|
wait_for_completion(&mcspi_dma->dma_tx_completion);
|
||||||
dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
|
dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
|
|
||||||
|
if (mcspi->fifo_depth > 0) {
|
||||||
|
irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
|
||||||
|
|
||||||
|
if (mcspi_wait_for_reg_bit(irqstat_reg,
|
||||||
|
OMAP2_MCSPI_IRQSTATUS_EOW) < 0)
|
||||||
|
dev_err(&spi->dev, "EOW timed out\n");
|
||||||
|
|
||||||
|
mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS,
|
||||||
|
OMAP2_MCSPI_IRQSTATUS_EOW);
|
||||||
|
}
|
||||||
|
|
||||||
/* for TX_ONLY mode, be sure all words have shifted out */
|
/* for TX_ONLY mode, be sure all words have shifted out */
|
||||||
if (rx == NULL) {
|
if (rx == NULL) {
|
||||||
if (mcspi_wait_for_reg_bit(chstat_reg,
|
chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
|
||||||
OMAP2_MCSPI_CHSTAT_TXS) < 0)
|
if (mcspi->fifo_depth > 0) {
|
||||||
|
wait_res = mcspi_wait_for_reg_bit(chstat_reg,
|
||||||
|
OMAP2_MCSPI_CHSTAT_TXFFE);
|
||||||
|
if (wait_res < 0)
|
||||||
|
dev_err(&spi->dev, "TXFFE timed out\n");
|
||||||
|
} else {
|
||||||
|
wait_res = mcspi_wait_for_reg_bit(chstat_reg,
|
||||||
|
OMAP2_MCSPI_CHSTAT_TXS);
|
||||||
|
if (wait_res < 0)
|
||||||
dev_err(&spi->dev, "TXS timed out\n");
|
dev_err(&spi->dev, "TXS timed out\n");
|
||||||
else if (mcspi_wait_for_reg_bit(chstat_reg,
|
}
|
||||||
OMAP2_MCSPI_CHSTAT_EOT) < 0)
|
if (wait_res >= 0 &&
|
||||||
|
(mcspi_wait_for_reg_bit(chstat_reg,
|
||||||
|
OMAP2_MCSPI_CHSTAT_EOT) < 0))
|
||||||
dev_err(&spi->dev, "EOT timed out\n");
|
dev_err(&spi->dev, "EOT timed out\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -830,12 +939,20 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
|
||||||
dma_cap_zero(mask);
|
dma_cap_zero(mask);
|
||||||
dma_cap_set(DMA_SLAVE, mask);
|
dma_cap_set(DMA_SLAVE, mask);
|
||||||
sig = mcspi_dma->dma_rx_sync_dev;
|
sig = mcspi_dma->dma_rx_sync_dev;
|
||||||
mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
|
|
||||||
|
mcspi_dma->dma_rx =
|
||||||
|
dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
|
||||||
|
&sig, &master->dev,
|
||||||
|
mcspi_dma->dma_rx_ch_name);
|
||||||
if (!mcspi_dma->dma_rx)
|
if (!mcspi_dma->dma_rx)
|
||||||
goto no_dma;
|
goto no_dma;
|
||||||
|
|
||||||
sig = mcspi_dma->dma_tx_sync_dev;
|
sig = mcspi_dma->dma_tx_sync_dev;
|
||||||
mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
|
mcspi_dma->dma_tx =
|
||||||
|
dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
|
||||||
|
&sig, &master->dev,
|
||||||
|
mcspi_dma->dma_tx_ch_name);
|
||||||
|
|
||||||
if (!mcspi_dma->dma_tx) {
|
if (!mcspi_dma->dma_tx) {
|
||||||
dma_release_channel(mcspi_dma->dma_rx);
|
dma_release_channel(mcspi_dma->dma_rx);
|
||||||
mcspi_dma->dma_rx = NULL;
|
mcspi_dma->dma_rx = NULL;
|
||||||
|
@ -857,12 +974,6 @@ static int omap2_mcspi_setup(struct spi_device *spi)
|
||||||
struct omap2_mcspi_dma *mcspi_dma;
|
struct omap2_mcspi_dma *mcspi_dma;
|
||||||
struct omap2_mcspi_cs *cs = spi->controller_state;
|
struct omap2_mcspi_cs *cs = spi->controller_state;
|
||||||
|
|
||||||
if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
|
|
||||||
dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
|
|
||||||
spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
|
||||||
|
|
||||||
if (!cs) {
|
if (!cs) {
|
||||||
|
@ -951,7 +1062,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
|
||||||
cs = spi->controller_state;
|
cs = spi->controller_state;
|
||||||
cd = spi->controller_data;
|
cd = spi->controller_data;
|
||||||
|
|
||||||
omap2_mcspi_set_enable(spi, 1);
|
omap2_mcspi_set_enable(spi, 0);
|
||||||
list_for_each_entry(t, &m->transfers, transfer_list) {
|
list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||||
if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
|
if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
|
||||||
status = -EINVAL;
|
status = -EINVAL;
|
||||||
|
@ -999,6 +1110,12 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
|
||||||
if (t->len) {
|
if (t->len) {
|
||||||
unsigned count;
|
unsigned count;
|
||||||
|
|
||||||
|
if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
|
||||||
|
(m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
|
||||||
|
omap2_mcspi_set_fifo(spi, t, 1);
|
||||||
|
|
||||||
|
omap2_mcspi_set_enable(spi, 1);
|
||||||
|
|
||||||
/* RX_ONLY mode needs dummy data in TX reg */
|
/* RX_ONLY mode needs dummy data in TX reg */
|
||||||
if (t->tx_buf == NULL)
|
if (t->tx_buf == NULL)
|
||||||
__raw_writel(0, cs->base
|
__raw_writel(0, cs->base
|
||||||
|
@ -1025,6 +1142,11 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
|
||||||
omap2_mcspi_force_cs(spi, 0);
|
omap2_mcspi_force_cs(spi, 0);
|
||||||
cs_active = 0;
|
cs_active = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
omap2_mcspi_set_enable(spi, 0);
|
||||||
|
|
||||||
|
if (mcspi->fifo_depth > 0)
|
||||||
|
omap2_mcspi_set_fifo(spi, t, 0);
|
||||||
}
|
}
|
||||||
/* Restore defaults if they were overriden */
|
/* Restore defaults if they were overriden */
|
||||||
if (par_override) {
|
if (par_override) {
|
||||||
|
@ -1045,8 +1167,10 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
|
||||||
|
|
||||||
omap2_mcspi_set_enable(spi, 0);
|
omap2_mcspi_set_enable(spi, 0);
|
||||||
|
|
||||||
m->status = status;
|
if (mcspi->fifo_depth > 0 && t)
|
||||||
|
omap2_mcspi_set_fifo(spi, t, 0);
|
||||||
|
|
||||||
|
m->status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int omap2_mcspi_transfer_one_message(struct spi_master *master,
|
static int omap2_mcspi_transfer_one_message(struct spi_master *master,
|
||||||
|
@ -1072,10 +1196,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
|
||||||
unsigned len = t->len;
|
unsigned len = t->len;
|
||||||
|
|
||||||
if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
|
if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
|
||||||
|| (len && !(rx_buf || tx_buf))
|
|| (len && !(rx_buf || tx_buf))) {
|
||||||
|| (t->bits_per_word &&
|
|
||||||
( t->bits_per_word < 4
|
|
||||||
|| t->bits_per_word > 32))) {
|
|
||||||
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
|
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
|
||||||
t->speed_hz,
|
t->speed_hz,
|
||||||
len,
|
len,
|
||||||
|
@ -1186,7 +1307,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
||||||
static int bus_num = 1;
|
static int bus_num = 1;
|
||||||
struct device_node *node = pdev->dev.of_node;
|
struct device_node *node = pdev->dev.of_node;
|
||||||
const struct of_device_id *match;
|
const struct of_device_id *match;
|
||||||
struct pinctrl *pinctrl;
|
|
||||||
|
|
||||||
master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
|
master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
|
||||||
if (master == NULL) {
|
if (master == NULL) {
|
||||||
|
@ -1196,7 +1316,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
/* the spi->mode bits understood by this driver: */
|
/* the spi->mode bits understood by this driver: */
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||||
master->setup = omap2_mcspi_setup;
|
master->setup = omap2_mcspi_setup;
|
||||||
master->prepare_transfer_hardware = omap2_prepare_transfer;
|
master->prepare_transfer_hardware = omap2_prepare_transfer;
|
||||||
master->unprepare_transfer_hardware = omap2_unprepare_transfer;
|
master->unprepare_transfer_hardware = omap2_unprepare_transfer;
|
||||||
|
@ -1204,7 +1324,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
||||||
master->cleanup = omap2_mcspi_cleanup;
|
master->cleanup = omap2_mcspi_cleanup;
|
||||||
master->dev.of_node = node;
|
master->dev.of_node = node;
|
||||||
|
|
||||||
dev_set_drvdata(&pdev->dev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
mcspi = spi_master_get_devdata(master);
|
mcspi = spi_master_get_devdata(master);
|
||||||
mcspi->master = master;
|
mcspi->master = master;
|
||||||
|
@ -1256,39 +1376,47 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
|
||||||
goto free_master;
|
goto free_master;
|
||||||
|
|
||||||
for (i = 0; i < master->num_chipselect; i++) {
|
for (i = 0; i < master->num_chipselect; i++) {
|
||||||
char dma_ch_name[14];
|
char *dma_rx_ch_name = mcspi->dma_channels[i].dma_rx_ch_name;
|
||||||
|
char *dma_tx_ch_name = mcspi->dma_channels[i].dma_tx_ch_name;
|
||||||
struct resource *dma_res;
|
struct resource *dma_res;
|
||||||
|
|
||||||
sprintf(dma_ch_name, "rx%d", i);
|
sprintf(dma_rx_ch_name, "rx%d", i);
|
||||||
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
|
if (!pdev->dev.of_node) {
|
||||||
dma_ch_name);
|
dma_res =
|
||||||
|
platform_get_resource_byname(pdev,
|
||||||
|
IORESOURCE_DMA,
|
||||||
|
dma_rx_ch_name);
|
||||||
if (!dma_res) {
|
if (!dma_res) {
|
||||||
dev_dbg(&pdev->dev, "cannot get DMA RX channel\n");
|
dev_dbg(&pdev->dev,
|
||||||
|
"cannot get DMA RX channel\n");
|
||||||
status = -ENODEV;
|
status = -ENODEV;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
|
mcspi->dma_channels[i].dma_rx_sync_dev =
|
||||||
sprintf(dma_ch_name, "tx%d", i);
|
dma_res->start;
|
||||||
dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
|
}
|
||||||
dma_ch_name);
|
sprintf(dma_tx_ch_name, "tx%d", i);
|
||||||
|
if (!pdev->dev.of_node) {
|
||||||
|
dma_res =
|
||||||
|
platform_get_resource_byname(pdev,
|
||||||
|
IORESOURCE_DMA,
|
||||||
|
dma_tx_ch_name);
|
||||||
if (!dma_res) {
|
if (!dma_res) {
|
||||||
dev_dbg(&pdev->dev, "cannot get DMA TX channel\n");
|
dev_dbg(&pdev->dev,
|
||||||
|
"cannot get DMA TX channel\n");
|
||||||
status = -ENODEV;
|
status = -ENODEV;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start;
|
mcspi->dma_channels[i].dma_tx_sync_dev =
|
||||||
|
dma_res->start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
goto dma_chnl_free;
|
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_use_autosuspend(&pdev->dev);
|
||||||
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
|
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
|
||||||
pm_runtime_enable(&pdev->dev);
|
pm_runtime_enable(&pdev->dev);
|
||||||
|
@ -1318,7 +1446,7 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
|
||||||
struct omap2_mcspi *mcspi;
|
struct omap2_mcspi *mcspi;
|
||||||
struct omap2_mcspi_dma *dma_channels;
|
struct omap2_mcspi_dma *dma_channels;
|
||||||
|
|
||||||
master = dev_get_drvdata(&pdev->dev);
|
master = platform_get_drvdata(pdev);
|
||||||
mcspi = spi_master_get_devdata(master);
|
mcspi = spi_master_get_devdata(master);
|
||||||
dma_channels = mcspi->dma_channels;
|
dma_channels = mcspi->dma_channels;
|
||||||
|
|
||||||
|
|
|
@ -428,7 +428,7 @@ static int orion_spi_probe(struct platform_device *pdev)
|
||||||
master->transfer_one_message = orion_spi_transfer_one_message;
|
master->transfer_one_message = orion_spi_transfer_one_message;
|
||||||
master->num_chipselect = ORION_NUM_CHIPSELECTS;
|
master->num_chipselect = ORION_NUM_CHIPSELECTS;
|
||||||
|
|
||||||
dev_set_drvdata(&pdev->dev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
spi = spi_master_get_devdata(master);
|
spi = spi_master_get_devdata(master);
|
||||||
spi->master = master;
|
spi->master = master;
|
||||||
|
@ -485,7 +485,7 @@ static int orion_spi_remove(struct platform_device *pdev)
|
||||||
struct resource *r;
|
struct resource *r;
|
||||||
struct orion_spi *spi;
|
struct orion_spi *spi;
|
||||||
|
|
||||||
master = dev_get_drvdata(&pdev->dev);
|
master = platform_get_drvdata(pdev);
|
||||||
spi = spi_master_get_devdata(master);
|
spi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
clk_disable_unprepare(spi->clk);
|
clk_disable_unprepare(spi->clk);
|
||||||
|
|
|
@ -190,12 +190,6 @@ static int spi_ppc4xx_setupxfer(struct spi_device *spi, struct spi_transfer *t)
|
||||||
speed = min(t->speed_hz, spi->max_speed_hz);
|
speed = min(t->speed_hz, spi->max_speed_hz);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bits_per_word != 8) {
|
|
||||||
dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
|
|
||||||
bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!speed || (speed > spi->max_speed_hz)) {
|
if (!speed || (speed > spi->max_speed_hz)) {
|
||||||
dev_err(&spi->dev, "invalid speed_hz (%d)\n", speed);
|
dev_err(&spi->dev, "invalid speed_hz (%d)\n", speed);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -229,12 +223,6 @@ static int spi_ppc4xx_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct spi_ppc4xx_cs *cs = spi->controller_state;
|
struct spi_ppc4xx_cs *cs = spi->controller_state;
|
||||||
|
|
||||||
if (spi->bits_per_word != 8) {
|
|
||||||
dev_err(&spi->dev, "invalid bits-per-word (%d)\n",
|
|
||||||
spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!spi->max_speed_hz) {
|
if (!spi->max_speed_hz) {
|
||||||
dev_err(&spi->dev, "invalid max_speed_hz (must be non-zero)\n");
|
dev_err(&spi->dev, "invalid max_speed_hz (must be non-zero)\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -406,7 +394,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
|
||||||
if (master == NULL)
|
if (master == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
master->dev.of_node = np;
|
master->dev.of_node = np;
|
||||||
dev_set_drvdata(dev, master);
|
platform_set_drvdata(op, master);
|
||||||
hw = spi_master_get_devdata(master);
|
hw = spi_master_get_devdata(master);
|
||||||
hw->master = spi_master_get(master);
|
hw->master = spi_master_get(master);
|
||||||
hw->dev = dev;
|
hw->dev = dev;
|
||||||
|
@ -465,6 +453,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op)
|
||||||
bbp->use_dma = 0;
|
bbp->use_dma = 0;
|
||||||
bbp->master->setup = spi_ppc4xx_setup;
|
bbp->master->setup = spi_ppc4xx_setup;
|
||||||
bbp->master->cleanup = spi_ppc4xx_cleanup;
|
bbp->master->cleanup = spi_ppc4xx_cleanup;
|
||||||
|
bbp->master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||||
|
|
||||||
/* the spi->mode bits understood by this driver: */
|
/* the spi->mode bits understood by this driver: */
|
||||||
bbp->master->mode_bits =
|
bbp->master->mode_bits =
|
||||||
|
@ -553,7 +542,6 @@ request_mem_error:
|
||||||
free_gpios:
|
free_gpios:
|
||||||
free_gpios(hw);
|
free_gpios(hw);
|
||||||
free_master:
|
free_master:
|
||||||
dev_set_drvdata(dev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
|
|
||||||
dev_err(dev, "initialization failed\n");
|
dev_err(dev, "initialization failed\n");
|
||||||
|
@ -562,11 +550,10 @@ free_master:
|
||||||
|
|
||||||
static int spi_ppc4xx_of_remove(struct platform_device *op)
|
static int spi_ppc4xx_of_remove(struct platform_device *op)
|
||||||
{
|
{
|
||||||
struct spi_master *master = dev_get_drvdata(&op->dev);
|
struct spi_master *master = platform_get_drvdata(op);
|
||||||
struct ppc4xx_spi *hw = spi_master_get_devdata(master);
|
struct ppc4xx_spi *hw = spi_master_get_devdata(master);
|
||||||
|
|
||||||
spi_bitbang_stop(&hw->bitbang);
|
spi_bitbang_stop(&hw->bitbang);
|
||||||
dev_set_drvdata(&op->dev, NULL);
|
|
||||||
release_mem_region(hw->mapbase, hw->mapsize);
|
release_mem_region(hw->mapbase, hw->mapsize);
|
||||||
free_irq(hw->irqnum, hw);
|
free_irq(hw->irqnum, hw);
|
||||||
iounmap(hw->regs);
|
iounmap(hw->regs);
|
||||||
|
|
|
@ -327,22 +327,23 @@ void pxa2xx_spi_dma_start(struct driver_data *drv_data)
|
||||||
int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
|
int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
|
||||||
{
|
{
|
||||||
struct pxa2xx_spi_master *pdata = drv_data->master_info;
|
struct pxa2xx_spi_master *pdata = drv_data->master_info;
|
||||||
|
struct device *dev = &drv_data->pdev->dev;
|
||||||
dma_cap_mask_t mask;
|
dma_cap_mask_t mask;
|
||||||
|
|
||||||
dma_cap_zero(mask);
|
dma_cap_zero(mask);
|
||||||
dma_cap_set(DMA_SLAVE, mask);
|
dma_cap_set(DMA_SLAVE, mask);
|
||||||
|
|
||||||
drv_data->dummy = devm_kzalloc(&drv_data->pdev->dev, SZ_2K, GFP_KERNEL);
|
drv_data->dummy = devm_kzalloc(dev, SZ_2K, GFP_KERNEL);
|
||||||
if (!drv_data->dummy)
|
if (!drv_data->dummy)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
drv_data->tx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
|
drv_data->tx_chan = dma_request_slave_channel_compat(mask,
|
||||||
pdata);
|
pxa2xx_spi_dma_filter, pdata, dev, "tx");
|
||||||
if (!drv_data->tx_chan)
|
if (!drv_data->tx_chan)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
drv_data->rx_chan = dma_request_channel(mask, pxa2xx_spi_dma_filter,
|
drv_data->rx_chan = dma_request_slave_channel_compat(mask,
|
||||||
pdata);
|
pxa2xx_spi_dma_filter, pdata, dev, "rx");
|
||||||
if (!drv_data->rx_chan) {
|
if (!drv_data->rx_chan) {
|
||||||
dma_release_channel(drv_data->tx_chan);
|
dma_release_channel(drv_data->tx_chan);
|
||||||
drv_data->tx_chan = NULL;
|
drv_data->tx_chan = NULL;
|
||||||
|
|
|
@ -881,21 +881,6 @@ static int setup(struct spi_device *spi)
|
||||||
rx_thres = RX_THRESH_DFLT;
|
rx_thres = RX_THRESH_DFLT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pxa25x_ssp_comp(drv_data)
|
|
||||||
&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
|
|
||||||
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
|
|
||||||
"b/w not 4-32 for type non-PXA25x_SSP\n",
|
|
||||||
drv_data->ssp_type, spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
} else if (pxa25x_ssp_comp(drv_data)
|
|
||||||
&& (spi->bits_per_word < 4
|
|
||||||
|| spi->bits_per_word > 16)) {
|
|
||||||
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
|
|
||||||
"b/w not 4-16 for type PXA25x_SSP\n",
|
|
||||||
drv_data->ssp_type, spi->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only alloc on first setup */
|
/* Only alloc on first setup */
|
||||||
chip = spi_get_ctldata(spi);
|
chip = spi_get_ctldata(spi);
|
||||||
if (!chip) {
|
if (!chip) {
|
||||||
|
@ -1011,9 +996,6 @@ static int setup(struct spi_device *spi)
|
||||||
chip->n_bytes = 4;
|
chip->n_bytes = 4;
|
||||||
chip->read = u32_reader;
|
chip->read = u32_reader;
|
||||||
chip->write = u32_writer;
|
chip->write = u32_writer;
|
||||||
} else {
|
|
||||||
dev_err(&spi->dev, "invalid wordsize\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
}
|
||||||
chip->bits_per_word = spi->bits_per_word;
|
chip->bits_per_word = spi->bits_per_word;
|
||||||
|
|
||||||
|
@ -1040,32 +1022,10 @@ static void cleanup(struct spi_device *spi)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
static int pxa2xx_spi_acpi_add_dma(struct acpi_resource *res, void *data)
|
|
||||||
{
|
|
||||||
struct pxa2xx_spi_master *pdata = data;
|
|
||||||
|
|
||||||
if (res->type == ACPI_RESOURCE_TYPE_FIXED_DMA) {
|
|
||||||
const struct acpi_resource_fixed_dma *dma;
|
|
||||||
|
|
||||||
dma = &res->data.fixed_dma;
|
|
||||||
if (pdata->tx_slave_id < 0) {
|
|
||||||
pdata->tx_slave_id = dma->request_lines;
|
|
||||||
pdata->tx_chan_id = dma->channels;
|
|
||||||
} else if (pdata->rx_slave_id < 0) {
|
|
||||||
pdata->rx_slave_id = dma->request_lines;
|
|
||||||
pdata->rx_chan_id = dma->channels;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tell the ACPI core to skip this resource */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct pxa2xx_spi_master *
|
static struct pxa2xx_spi_master *
|
||||||
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
|
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct pxa2xx_spi_master *pdata;
|
struct pxa2xx_spi_master *pdata;
|
||||||
struct list_head resource_list;
|
|
||||||
struct acpi_device *adev;
|
struct acpi_device *adev;
|
||||||
struct ssp_device *ssp;
|
struct ssp_device *ssp;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
|
@ -1091,7 +1051,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
|
||||||
ssp->phys_base = res->start;
|
ssp->phys_base = res->start;
|
||||||
ssp->mmio_base = devm_ioremap_resource(&pdev->dev, res);
|
ssp->mmio_base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(ssp->mmio_base))
|
if (IS_ERR(ssp->mmio_base))
|
||||||
return PTR_ERR(ssp->mmio_base);
|
return NULL;
|
||||||
|
|
||||||
ssp->clk = devm_clk_get(&pdev->dev, NULL);
|
ssp->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
ssp->irq = platform_get_irq(pdev, 0);
|
ssp->irq = platform_get_irq(pdev, 0);
|
||||||
|
@ -1103,15 +1063,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
|
||||||
ssp->port_id = devid;
|
ssp->port_id = devid;
|
||||||
|
|
||||||
pdata->num_chipselect = 1;
|
pdata->num_chipselect = 1;
|
||||||
pdata->rx_slave_id = -1;
|
pdata->enable_dma = true;
|
||||||
pdata->tx_slave_id = -1;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&resource_list);
|
|
||||||
acpi_dev_get_resources(adev, &resource_list, pxa2xx_spi_acpi_add_dma,
|
|
||||||
pdata);
|
|
||||||
acpi_dev_free_resource_list(&resource_list);
|
|
||||||
|
|
||||||
pdata->enable_dma = pdata->rx_slave_id >= 0 && pdata->tx_slave_id >= 0;
|
|
||||||
|
|
||||||
return pdata;
|
return pdata;
|
||||||
}
|
}
|
||||||
|
@ -1119,6 +1071,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
|
||||||
static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
|
static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
|
||||||
{ "INT33C0", 0 },
|
{ "INT33C0", 0 },
|
||||||
{ "INT33C1", 0 },
|
{ "INT33C1", 0 },
|
||||||
|
{ "80860F0E", 0 },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
|
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
|
||||||
|
@ -1190,11 +1143,13 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
||||||
drv_data->ioaddr = ssp->mmio_base;
|
drv_data->ioaddr = ssp->mmio_base;
|
||||||
drv_data->ssdr_physical = ssp->phys_base + SSDR;
|
drv_data->ssdr_physical = ssp->phys_base + SSDR;
|
||||||
if (pxa25x_ssp_comp(drv_data)) {
|
if (pxa25x_ssp_comp(drv_data)) {
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
|
||||||
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
|
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
|
||||||
drv_data->dma_cr1 = 0;
|
drv_data->dma_cr1 = 0;
|
||||||
drv_data->clear_sr = SSSR_ROR;
|
drv_data->clear_sr = SSSR_ROR;
|
||||||
drv_data->mask_sr = SSSR_RFS | SSSR_TFS | SSSR_ROR;
|
drv_data->mask_sr = SSSR_RFS | SSSR_TFS | SSSR_ROR;
|
||||||
} else {
|
} else {
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||||
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
|
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE;
|
||||||
drv_data->dma_cr1 = DEFAULT_DMA_CR1;
|
drv_data->dma_cr1 = DEFAULT_DMA_CR1;
|
||||||
drv_data->clear_sr = SSSR_ROR | SSSR_TINT;
|
drv_data->clear_sr = SSSR_ROR | SSSR_TINT;
|
||||||
|
@ -1214,7 +1169,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
||||||
if (platform_info->enable_dma) {
|
if (platform_info->enable_dma) {
|
||||||
status = pxa2xx_spi_dma_setup(drv_data);
|
status = pxa2xx_spi_dma_setup(drv_data);
|
||||||
if (status) {
|
if (status) {
|
||||||
dev_warn(dev, "failed to setup DMA, using PIO\n");
|
dev_dbg(dev, "no DMA channels available, using PIO\n");
|
||||||
platform_info->enable_dma = false;
|
platform_info->enable_dma = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1299,9 +1254,6 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
|
||||||
/* Disconnect from the SPI framework */
|
/* Disconnect from the SPI framework */
|
||||||
spi_unregister_master(drv_data->master);
|
spi_unregister_master(drv_data->master);
|
||||||
|
|
||||||
/* Prevent double remove */
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -719,7 +719,7 @@ static void rspi_release_dma(struct rspi_data *rspi)
|
||||||
|
|
||||||
static int rspi_remove(struct platform_device *pdev)
|
static int rspi_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct rspi_data *rspi = dev_get_drvdata(&pdev->dev);
|
struct rspi_data *rspi = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
spi_unregister_master(rspi->master);
|
spi_unregister_master(rspi->master);
|
||||||
rspi_release_dma(rspi);
|
rspi_release_dma(rspi);
|
||||||
|
@ -759,7 +759,7 @@ static int rspi_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
rspi = spi_master_get_devdata(master);
|
rspi = spi_master_get_devdata(master);
|
||||||
dev_set_drvdata(&pdev->dev, rspi);
|
platform_set_drvdata(pdev, rspi);
|
||||||
|
|
||||||
rspi->master = master;
|
rspi->master = master;
|
||||||
rspi->addr = ioremap(res->start, resource_size(res));
|
rspi->addr = ioremap(res->start, resource_size(res));
|
||||||
|
|
|
@ -667,8 +667,6 @@ static int s3c24xx_spi_remove(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
struct s3c24xx_spi *hw = platform_get_drvdata(dev);
|
struct s3c24xx_spi *hw = platform_get_drvdata(dev);
|
||||||
|
|
||||||
platform_set_drvdata(dev, NULL);
|
|
||||||
|
|
||||||
spi_bitbang_stop(&hw->bitbang);
|
spi_bitbang_stop(&hw->bitbang);
|
||||||
|
|
||||||
clk_disable(hw->clk);
|
clk_disable(hw->clk);
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_SPI_PORTS 3
|
#define MAX_SPI_PORTS 3
|
||||||
|
#define S3C64XX_SPI_QUIRK_POLL (1 << 0)
|
||||||
|
|
||||||
/* Registers and bit-fields */
|
/* Registers and bit-fields */
|
||||||
|
|
||||||
|
@ -130,6 +131,7 @@
|
||||||
#define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT
|
#define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT
|
||||||
|
|
||||||
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
|
#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
|
||||||
|
#define is_polling(x) (x->port_conf->quirks & S3C64XX_SPI_QUIRK_POLL)
|
||||||
|
|
||||||
#define RXBUSY (1<<2)
|
#define RXBUSY (1<<2)
|
||||||
#define TXBUSY (1<<3)
|
#define TXBUSY (1<<3)
|
||||||
|
@ -158,6 +160,7 @@ struct s3c64xx_spi_port_config {
|
||||||
int fifo_lvl_mask[MAX_SPI_PORTS];
|
int fifo_lvl_mask[MAX_SPI_PORTS];
|
||||||
int rx_lvl_offset;
|
int rx_lvl_offset;
|
||||||
int tx_st_done;
|
int tx_st_done;
|
||||||
|
int quirks;
|
||||||
bool high_speed;
|
bool high_speed;
|
||||||
bool clk_from_cmu;
|
bool clk_from_cmu;
|
||||||
};
|
};
|
||||||
|
@ -205,6 +208,7 @@ struct s3c64xx_spi_driver_data {
|
||||||
struct s3c64xx_spi_port_config *port_conf;
|
struct s3c64xx_spi_port_config *port_conf;
|
||||||
unsigned int port_id;
|
unsigned int port_id;
|
||||||
unsigned long gpios[4];
|
unsigned long gpios[4];
|
||||||
|
bool cs_gpio;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
|
static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
|
||||||
|
@ -344,8 +348,12 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
|
||||||
{
|
{
|
||||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
|
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
|
||||||
|
|
||||||
/* Acquire DMA channels */
|
/*
|
||||||
while (!acquire_dma(sdd))
|
* If DMA resource was not available during
|
||||||
|
* probe, no need to continue with dma requests
|
||||||
|
* else Acquire DMA channels
|
||||||
|
*/
|
||||||
|
while (!is_polling(sdd) && !acquire_dma(sdd))
|
||||||
usleep_range(10000, 11000);
|
usleep_range(10000, 11000);
|
||||||
|
|
||||||
pm_runtime_get_sync(&sdd->pdev->dev);
|
pm_runtime_get_sync(&sdd->pdev->dev);
|
||||||
|
@ -358,9 +366,12 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
|
||||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
|
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
|
||||||
|
|
||||||
/* Free DMA channels */
|
/* Free DMA channels */
|
||||||
sdd->ops->release((enum dma_ch)sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
|
if (!is_polling(sdd)) {
|
||||||
sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
|
sdd->ops->release((enum dma_ch)sdd->rx_dma.ch,
|
||||||
|
&s3c64xx_spi_dma_client);
|
||||||
|
sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
|
||||||
|
&s3c64xx_spi_dma_client);
|
||||||
|
}
|
||||||
pm_runtime_put(&sdd->pdev->dev);
|
pm_runtime_put(&sdd->pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -464,8 +475,10 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
|
||||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
|
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
|
||||||
|
|
||||||
/* Free DMA channels */
|
/* Free DMA channels */
|
||||||
|
if (!is_polling(sdd)) {
|
||||||
dma_release_channel(sdd->rx_dma.ch);
|
dma_release_channel(sdd->rx_dma.ch);
|
||||||
dma_release_channel(sdd->tx_dma.ch);
|
dma_release_channel(sdd->tx_dma.ch);
|
||||||
|
}
|
||||||
|
|
||||||
pm_runtime_put(&sdd->pdev->dev);
|
pm_runtime_put(&sdd->pdev->dev);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -558,6 +571,7 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
|
||||||
if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
|
if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
|
||||||
/* Deselect the last toggled device */
|
/* Deselect the last toggled device */
|
||||||
cs = sdd->tgl_spi->controller_data;
|
cs = sdd->tgl_spi->controller_data;
|
||||||
|
if (sdd->cs_gpio)
|
||||||
gpio_set_value(cs->line,
|
gpio_set_value(cs->line,
|
||||||
spi->mode & SPI_CS_HIGH ? 0 : 1);
|
spi->mode & SPI_CS_HIGH ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
@ -565,7 +579,32 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
|
||||||
}
|
}
|
||||||
|
|
||||||
cs = spi->controller_data;
|
cs = spi->controller_data;
|
||||||
|
if (sdd->cs_gpio)
|
||||||
gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0);
|
gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0);
|
||||||
|
|
||||||
|
/* Start the signals */
|
||||||
|
writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
|
||||||
|
int timeout_ms)
|
||||||
|
{
|
||||||
|
void __iomem *regs = sdd->regs;
|
||||||
|
unsigned long val = 1;
|
||||||
|
u32 status;
|
||||||
|
|
||||||
|
/* max fifo depth available */
|
||||||
|
u32 max_fifo = (FIFO_LVL_MASK(sdd) >> 1) + 1;
|
||||||
|
|
||||||
|
if (timeout_ms)
|
||||||
|
val = msecs_to_loops(timeout_ms);
|
||||||
|
|
||||||
|
do {
|
||||||
|
status = readl(regs + S3C64XX_SPI_STATUS);
|
||||||
|
} while (RX_FIFO_LVL(status, sdd) < max_fifo && --val);
|
||||||
|
|
||||||
|
/* return the actual received data length */
|
||||||
|
return RX_FIFO_LVL(status, sdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
|
static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
|
||||||
|
@ -590,20 +629,19 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
|
||||||
} while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
|
} while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!val)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
if (dma_mode) {
|
if (dma_mode) {
|
||||||
u32 status;
|
u32 status;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* If the previous xfer was completed within timeout, then
|
||||||
|
* proceed further else return -EIO.
|
||||||
* DmaTx returns after simply writing data in the FIFO,
|
* DmaTx returns after simply writing data in the FIFO,
|
||||||
* w/o waiting for real transmission on the bus to finish.
|
* w/o waiting for real transmission on the bus to finish.
|
||||||
* DmaRx returns only after Dma read data from FIFO which
|
* DmaRx returns only after Dma read data from FIFO which
|
||||||
* needs bus transmission to finish, so we don't worry if
|
* needs bus transmission to finish, so we don't worry if
|
||||||
* Xfer involved Rx(with or without Tx).
|
* Xfer involved Rx(with or without Tx).
|
||||||
*/
|
*/
|
||||||
if (xfer->rx_buf == NULL) {
|
if (val && !xfer->rx_buf) {
|
||||||
val = msecs_to_loops(10);
|
val = msecs_to_loops(10);
|
||||||
status = readl(regs + S3C64XX_SPI_STATUS);
|
status = readl(regs + S3C64XX_SPI_STATUS);
|
||||||
while ((TX_FIFO_LVL(status, sdd)
|
while ((TX_FIFO_LVL(status, sdd)
|
||||||
|
@ -613,30 +651,54 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
|
||||||
status = readl(regs + S3C64XX_SPI_STATUS);
|
status = readl(regs + S3C64XX_SPI_STATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If timed out while checking rx/tx status return error */
|
||||||
if (!val)
|
if (!val)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
int loops;
|
||||||
|
u32 cpy_len;
|
||||||
|
u8 *buf;
|
||||||
|
|
||||||
/* If it was only Tx */
|
/* If it was only Tx */
|
||||||
if (xfer->rx_buf == NULL) {
|
if (!xfer->rx_buf) {
|
||||||
sdd->state &= ~TXBUSY;
|
sdd->state &= ~TXBUSY;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the receive length is bigger than the controller fifo
|
||||||
|
* size, calculate the loops and read the fifo as many times.
|
||||||
|
* loops = length / max fifo size (calculated by using the
|
||||||
|
* fifo mask).
|
||||||
|
* For any size less than the fifo size the below code is
|
||||||
|
* executed atleast once.
|
||||||
|
*/
|
||||||
|
loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
|
||||||
|
buf = xfer->rx_buf;
|
||||||
|
do {
|
||||||
|
/* wait for data to be received in the fifo */
|
||||||
|
cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
|
||||||
|
(loops ? ms : 0));
|
||||||
|
|
||||||
switch (sdd->cur_bpw) {
|
switch (sdd->cur_bpw) {
|
||||||
case 32:
|
case 32:
|
||||||
ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
|
ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
|
||||||
xfer->rx_buf, xfer->len / 4);
|
buf, cpy_len / 4);
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
|
ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
|
||||||
xfer->rx_buf, xfer->len / 2);
|
buf, cpy_len / 2);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
|
ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
|
||||||
xfer->rx_buf, xfer->len);
|
buf, cpy_len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf = buf + cpy_len;
|
||||||
|
} while (loops--);
|
||||||
sdd->state &= ~RXBUSY;
|
sdd->state &= ~RXBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,7 +713,11 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
|
||||||
if (sdd->tgl_spi == spi)
|
if (sdd->tgl_spi == spi)
|
||||||
sdd->tgl_spi = NULL;
|
sdd->tgl_spi = NULL;
|
||||||
|
|
||||||
|
if (sdd->cs_gpio)
|
||||||
gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1);
|
gpio_set_value(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1);
|
||||||
|
|
||||||
|
/* Quiese the signals */
|
||||||
|
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
||||||
|
@ -733,7 +799,7 @@ static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
|
||||||
struct device *dev = &sdd->pdev->dev;
|
struct device *dev = &sdd->pdev->dev;
|
||||||
struct spi_transfer *xfer;
|
struct spi_transfer *xfer;
|
||||||
|
|
||||||
if (msg->is_dma_mapped)
|
if (is_polling(sdd) || msg->is_dma_mapped)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* First mark all xfer unmapped */
|
/* First mark all xfer unmapped */
|
||||||
|
@ -782,7 +848,7 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
|
||||||
struct device *dev = &sdd->pdev->dev;
|
struct device *dev = &sdd->pdev->dev;
|
||||||
struct spi_transfer *xfer;
|
struct spi_transfer *xfer;
|
||||||
|
|
||||||
if (msg->is_dma_mapped)
|
if (is_polling(sdd) || msg->is_dma_mapped)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
|
||||||
|
@ -861,8 +927,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
|
||||||
|
|
||||||
/* Polling method for xfers not bigger than FIFO capacity */
|
/* Polling method for xfers not bigger than FIFO capacity */
|
||||||
use_dma = 0;
|
use_dma = 0;
|
||||||
if (sdd->rx_dma.ch && sdd->tx_dma.ch &&
|
if (!is_polling(sdd) &&
|
||||||
(xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1)))
|
(sdd->rx_dma.ch && sdd->tx_dma.ch &&
|
||||||
|
(xfer->len > ((FIFO_LVL_MASK(sdd) >> 1) + 1))))
|
||||||
use_dma = 1;
|
use_dma = 1;
|
||||||
|
|
||||||
spin_lock_irqsave(&sdd->lock, flags);
|
spin_lock_irqsave(&sdd->lock, flags);
|
||||||
|
@ -876,17 +943,10 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
|
||||||
/* Slave Select */
|
/* Slave Select */
|
||||||
enable_cs(sdd, spi);
|
enable_cs(sdd, spi);
|
||||||
|
|
||||||
/* Start the signals */
|
|
||||||
writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&sdd->lock, flags);
|
spin_unlock_irqrestore(&sdd->lock, flags);
|
||||||
|
|
||||||
status = wait_for_xfer(sdd, xfer, use_dma);
|
status = wait_for_xfer(sdd, xfer, use_dma);
|
||||||
|
|
||||||
/* Quiese the signals */
|
|
||||||
writel(S3C64XX_SPI_SLAVE_SIG_INACT,
|
|
||||||
sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
|
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
|
||||||
xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
|
xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
|
||||||
|
@ -942,8 +1002,10 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
|
||||||
{
|
{
|
||||||
struct s3c64xx_spi_csinfo *cs;
|
struct s3c64xx_spi_csinfo *cs;
|
||||||
struct device_node *slave_np, *data_np = NULL;
|
struct device_node *slave_np, *data_np = NULL;
|
||||||
|
struct s3c64xx_spi_driver_data *sdd;
|
||||||
u32 fb_delay = 0;
|
u32 fb_delay = 0;
|
||||||
|
|
||||||
|
sdd = spi_master_get_devdata(spi->master);
|
||||||
slave_np = spi->dev.of_node;
|
slave_np = spi->dev.of_node;
|
||||||
if (!slave_np) {
|
if (!slave_np) {
|
||||||
dev_err(&spi->dev, "device node not found\n");
|
dev_err(&spi->dev, "device node not found\n");
|
||||||
|
@ -963,7 +1025,10 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The CS line is asserted/deasserted by the gpio pin */
|
||||||
|
if (sdd->cs_gpio)
|
||||||
cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
|
cs->line = of_get_named_gpio(data_np, "cs-gpio", 0);
|
||||||
|
|
||||||
if (!gpio_is_valid(cs->line)) {
|
if (!gpio_is_valid(cs->line)) {
|
||||||
dev_err(&spi->dev, "chip select gpio is not specified or invalid\n");
|
dev_err(&spi->dev, "chip select gpio is not specified or invalid\n");
|
||||||
kfree(cs);
|
kfree(cs);
|
||||||
|
@ -1003,7 +1068,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!spi_get_ctldata(spi)) {
|
/* Request gpio only if cs line is asserted by gpio pins */
|
||||||
|
if (sdd->cs_gpio) {
|
||||||
err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH,
|
err = gpio_request_one(cs->line, GPIOF_OUT_INIT_HIGH,
|
||||||
dev_name(&spi->dev));
|
dev_name(&spi->dev));
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1012,9 +1078,11 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
|
||||||
cs->line, err);
|
cs->line, err);
|
||||||
goto err_gpio_req;
|
goto err_gpio_req;
|
||||||
}
|
}
|
||||||
spi_set_ctldata(spi, cs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!spi_get_ctldata(spi))
|
||||||
|
spi_set_ctldata(spi, cs);
|
||||||
|
|
||||||
sci = sdd->cntrlr_info;
|
sci = sdd->cntrlr_info;
|
||||||
|
|
||||||
spin_lock_irqsave(&sdd->lock, flags);
|
spin_lock_irqsave(&sdd->lock, flags);
|
||||||
|
@ -1092,8 +1160,10 @@ err_gpio_req:
|
||||||
static void s3c64xx_spi_cleanup(struct spi_device *spi)
|
static void s3c64xx_spi_cleanup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi);
|
struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi);
|
||||||
|
struct s3c64xx_spi_driver_data *sdd;
|
||||||
|
|
||||||
if (cs) {
|
sdd = spi_master_get_devdata(spi->master);
|
||||||
|
if (cs && sdd->cs_gpio) {
|
||||||
gpio_free(cs->line);
|
gpio_free(cs->line);
|
||||||
if (spi->dev.of_node)
|
if (spi->dev.of_node)
|
||||||
kfree(cs);
|
kfree(cs);
|
||||||
|
@ -1270,7 +1340,11 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
||||||
sdd->cntrlr_info = sci;
|
sdd->cntrlr_info = sci;
|
||||||
sdd->pdev = pdev;
|
sdd->pdev = pdev;
|
||||||
sdd->sfr_start = mem_res->start;
|
sdd->sfr_start = mem_res->start;
|
||||||
|
sdd->cs_gpio = true;
|
||||||
if (pdev->dev.of_node) {
|
if (pdev->dev.of_node) {
|
||||||
|
if (!of_find_property(pdev->dev.of_node, "cs-gpio", NULL))
|
||||||
|
sdd->cs_gpio = false;
|
||||||
|
|
||||||
ret = of_alias_get_id(pdev->dev.of_node, "spi");
|
ret = of_alias_get_id(pdev->dev.of_node, "spi");
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
|
dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
|
||||||
|
@ -1287,18 +1361,18 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
||||||
if (!sdd->pdev->dev.of_node) {
|
if (!sdd->pdev->dev.of_node) {
|
||||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
dev_err(&pdev->dev, "Unable to get SPI tx dma "
|
dev_warn(&pdev->dev, "Unable to get SPI tx dma "
|
||||||
"resource\n");
|
"resource. Switching to poll mode\n");
|
||||||
return -ENXIO;
|
sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
|
||||||
}
|
} else
|
||||||
sdd->tx_dma.dmach = res->start;
|
sdd->tx_dma.dmach = res->start;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
dev_err(&pdev->dev, "Unable to get SPI rx dma "
|
dev_warn(&pdev->dev, "Unable to get SPI rx dma "
|
||||||
"resource\n");
|
"resource. Switching to poll mode\n");
|
||||||
return -ENXIO;
|
sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL;
|
||||||
}
|
} else
|
||||||
sdd->rx_dma.dmach = res->start;
|
sdd->rx_dma.dmach = res->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1314,7 +1388,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
||||||
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
|
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
|
||||||
master->num_chipselect = sci->num_cs;
|
master->num_chipselect = sci->num_cs;
|
||||||
master->dma_alignment = 8;
|
master->dma_alignment = 8;
|
||||||
master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
|
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
|
||||||
|
SPI_BPW_MASK(8);
|
||||||
/* the spi->mode bits understood by this driver: */
|
/* the spi->mode bits understood by this driver: */
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
||||||
|
|
||||||
|
@ -1399,7 +1474,6 @@ err3:
|
||||||
err2:
|
err2:
|
||||||
clk_disable_unprepare(sdd->clk);
|
clk_disable_unprepare(sdd->clk);
|
||||||
err0:
|
err0:
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1420,7 +1494,6 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
clk_disable_unprepare(sdd->clk);
|
clk_disable_unprepare(sdd->clk);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1535,6 +1608,15 @@ static struct s3c64xx_spi_port_config exynos4_spi_port_config = {
|
||||||
.clk_from_cmu = true,
|
.clk_from_cmu = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct s3c64xx_spi_port_config exynos5440_spi_port_config = {
|
||||||
|
.fifo_lvl_mask = { 0x1ff },
|
||||||
|
.rx_lvl_offset = 15,
|
||||||
|
.tx_st_done = 25,
|
||||||
|
.high_speed = true,
|
||||||
|
.clk_from_cmu = true,
|
||||||
|
.quirks = S3C64XX_SPI_QUIRK_POLL,
|
||||||
|
};
|
||||||
|
|
||||||
static struct platform_device_id s3c64xx_spi_driver_ids[] = {
|
static struct platform_device_id s3c64xx_spi_driver_ids[] = {
|
||||||
{
|
{
|
||||||
.name = "s3c2443-spi",
|
.name = "s3c2443-spi",
|
||||||
|
@ -1558,15 +1640,16 @@ static struct platform_device_id s3c64xx_spi_driver_ids[] = {
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
|
||||||
static const struct of_device_id s3c64xx_spi_dt_match[] = {
|
static const struct of_device_id s3c64xx_spi_dt_match[] = {
|
||||||
{ .compatible = "samsung,exynos4210-spi",
|
{ .compatible = "samsung,exynos4210-spi",
|
||||||
.data = (void *)&exynos4_spi_port_config,
|
.data = (void *)&exynos4_spi_port_config,
|
||||||
},
|
},
|
||||||
|
{ .compatible = "samsung,exynos5440-spi",
|
||||||
|
.data = (void *)&exynos5440_spi_port_config,
|
||||||
|
},
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
|
MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
|
||||||
#endif /* CONFIG_OF */
|
|
||||||
|
|
||||||
static struct platform_driver s3c64xx_spi_driver = {
|
static struct platform_driver s3c64xx_spi_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
|
|
|
@ -297,7 +297,7 @@ static int hspi_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
hspi = spi_master_get_devdata(master);
|
hspi = spi_master_get_devdata(master);
|
||||||
dev_set_drvdata(&pdev->dev, hspi);
|
platform_set_drvdata(pdev, hspi);
|
||||||
|
|
||||||
/* init hspi */
|
/* init hspi */
|
||||||
hspi->master = master;
|
hspi->master = master;
|
||||||
|
@ -341,7 +341,7 @@ static int hspi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
static int hspi_remove(struct platform_device *pdev)
|
static int hspi_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct hspi_priv *hspi = dev_get_drvdata(&pdev->dev);
|
struct hspi_priv *hspi = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
|
|
|
@ -434,7 +434,7 @@ static irqreturn_t spi_sh_irq(int irq, void *_ss)
|
||||||
|
|
||||||
static int spi_sh_remove(struct platform_device *pdev)
|
static int spi_sh_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct spi_sh_data *ss = dev_get_drvdata(&pdev->dev);
|
struct spi_sh_data *ss = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
spi_unregister_master(ss->master);
|
spi_unregister_master(ss->master);
|
||||||
destroy_workqueue(ss->workqueue);
|
destroy_workqueue(ss->workqueue);
|
||||||
|
@ -471,7 +471,7 @@ static int spi_sh_probe(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
ss = spi_master_get_devdata(master);
|
ss = spi_master_get_devdata(master);
|
||||||
dev_set_drvdata(&pdev->dev, ss);
|
platform_set_drvdata(pdev, ss);
|
||||||
|
|
||||||
switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
|
switch (res->flags & IORESOURCE_MEM_TYPE_MASK) {
|
||||||
case IORESOURCE_MEM_8BIT:
|
case IORESOURCE_MEM_8BIT:
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/spi/spi_bitbang.h>
|
#include <linux/spi/spi_bitbang.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
|
||||||
|
|
||||||
#define DRIVER_NAME "sirfsoc_spi"
|
#define DRIVER_NAME "sirfsoc_spi"
|
||||||
|
|
||||||
|
@ -127,7 +126,6 @@ struct sirfsoc_spi {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
u32 ctrl_freq; /* SPI controller clock speed */
|
u32 ctrl_freq; /* SPI controller clock speed */
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct pinctrl *p;
|
|
||||||
|
|
||||||
/* rx & tx bufs from the spi_transfer */
|
/* rx & tx bufs from the spi_transfer */
|
||||||
const void *tx;
|
const void *tx;
|
||||||
|
@ -142,9 +140,6 @@ struct sirfsoc_spi {
|
||||||
unsigned int left_tx_cnt;
|
unsigned int left_tx_cnt;
|
||||||
unsigned int left_rx_cnt;
|
unsigned int left_rx_cnt;
|
||||||
|
|
||||||
/* tasklet to push tx msg into FIFO */
|
|
||||||
struct tasklet_struct tasklet_tx;
|
|
||||||
|
|
||||||
int chipselect[0];
|
int chipselect[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -236,17 +231,6 @@ static void spi_sirfsoc_tx_word_u32(struct sirfsoc_spi *sspi)
|
||||||
sspi->left_tx_cnt--;
|
sspi->left_tx_cnt--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spi_sirfsoc_tasklet_tx(unsigned long arg)
|
|
||||||
{
|
|
||||||
struct sirfsoc_spi *sspi = (struct sirfsoc_spi *)arg;
|
|
||||||
|
|
||||||
/* Fill Tx FIFO while there are left words to be transmitted */
|
|
||||||
while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) &
|
|
||||||
SIRFSOC_SPI_FIFO_FULL)) &&
|
|
||||||
sspi->left_tx_cnt)
|
|
||||||
sspi->tx_word(sspi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
|
static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct sirfsoc_spi *sspi = dev_id;
|
struct sirfsoc_spi *sspi = dev_id;
|
||||||
|
@ -261,25 +245,25 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
|
||||||
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spi_stat & SIRFSOC_SPI_FRM_END) {
|
if (spi_stat & (SIRFSOC_SPI_FRM_END
|
||||||
|
| SIRFSOC_SPI_RXFIFO_THD_REACH))
|
||||||
while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
|
while (!((readl(sspi->base + SIRFSOC_SPI_RXFIFO_STATUS)
|
||||||
& SIRFSOC_SPI_FIFO_EMPTY)) &&
|
& SIRFSOC_SPI_FIFO_EMPTY)) &&
|
||||||
sspi->left_rx_cnt)
|
sspi->left_rx_cnt)
|
||||||
sspi->rx_word(sspi);
|
sspi->rx_word(sspi);
|
||||||
|
|
||||||
|
if (spi_stat & (SIRFSOC_SPI_FIFO_EMPTY
|
||||||
|
| SIRFSOC_SPI_TXFIFO_THD_REACH))
|
||||||
|
while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS)
|
||||||
|
& SIRFSOC_SPI_FIFO_FULL)) &&
|
||||||
|
sspi->left_tx_cnt)
|
||||||
|
sspi->tx_word(sspi);
|
||||||
|
|
||||||
/* Received all words */
|
/* Received all words */
|
||||||
if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
|
if ((sspi->left_rx_cnt == 0) && (sspi->left_tx_cnt == 0)) {
|
||||||
complete(&sspi->done);
|
complete(&sspi->done);
|
||||||
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (spi_stat & SIRFSOC_SPI_RXFIFO_THD_REACH ||
|
|
||||||
spi_stat & SIRFSOC_SPI_TXFIFO_THD_REACH ||
|
|
||||||
spi_stat & SIRFSOC_SPI_RX_FIFO_FULL ||
|
|
||||||
spi_stat & SIRFSOC_SPI_TXFIFO_EMPTY)
|
|
||||||
tasklet_schedule(&sspi->tasklet_tx);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,9 +410,7 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||||
SIRFSOC_SPI_FIFO_WIDTH_DWORD;
|
SIRFSOC_SPI_FIFO_WIDTH_DWORD;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(&spi->dev, "Bits per word %d not supported\n",
|
BUG();
|
||||||
bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(spi->mode & SPI_CS_HIGH))
|
if (!(spi->mode & SPI_CS_HIGH))
|
||||||
|
@ -556,26 +538,20 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
||||||
sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer;
|
sspi->bitbang.txrx_bufs = spi_sirfsoc_transfer;
|
||||||
sspi->bitbang.master->setup = spi_sirfsoc_setup;
|
sspi->bitbang.master->setup = spi_sirfsoc_setup;
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) |
|
||||||
|
SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
|
||||||
sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
|
sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
sspi->p = pinctrl_get_select_default(&pdev->dev);
|
|
||||||
ret = IS_ERR(sspi->p);
|
|
||||||
if (ret)
|
|
||||||
goto free_master;
|
|
||||||
|
|
||||||
sspi->clk = clk_get(&pdev->dev, NULL);
|
sspi->clk = clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(sspi->clk)) {
|
if (IS_ERR(sspi->clk)) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto free_pin;
|
goto free_master;
|
||||||
}
|
}
|
||||||
clk_prepare_enable(sspi->clk);
|
clk_prepare_enable(sspi->clk);
|
||||||
sspi->ctrl_freq = clk_get_rate(sspi->clk);
|
sspi->ctrl_freq = clk_get_rate(sspi->clk);
|
||||||
|
|
||||||
init_completion(&sspi->done);
|
init_completion(&sspi->done);
|
||||||
|
|
||||||
tasklet_init(&sspi->tasklet_tx, spi_sirfsoc_tasklet_tx,
|
|
||||||
(unsigned long)sspi);
|
|
||||||
|
|
||||||
writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
||||||
writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
|
writel(SIRFSOC_SPI_FIFO_RESET, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
|
||||||
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
|
||||||
|
@ -594,8 +570,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
||||||
free_clk:
|
free_clk:
|
||||||
clk_disable_unprepare(sspi->clk);
|
clk_disable_unprepare(sspi->clk);
|
||||||
clk_put(sspi->clk);
|
clk_put(sspi->clk);
|
||||||
free_pin:
|
|
||||||
pinctrl_put(sspi->p);
|
|
||||||
free_master:
|
free_master:
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
err_cs:
|
err_cs:
|
||||||
|
@ -618,7 +592,6 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
clk_disable_unprepare(sspi->clk);
|
clk_disable_unprepare(sspi->clk);
|
||||||
clk_put(sspi->clk);
|
clk_put(sspi->clk);
|
||||||
pinctrl_put(sspi->p);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1041,7 +1041,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
|
||||||
dev_err(&pdev->dev, "master allocation failed\n");
|
dev_err(&pdev->dev, "master allocation failed\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
dev_set_drvdata(&pdev->dev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
tspi = spi_master_get_devdata(master);
|
tspi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
/* Parse DT */
|
/* Parse DT */
|
||||||
|
@ -1152,7 +1152,7 @@ exit_free_master:
|
||||||
|
|
||||||
static int tegra_spi_remove(struct platform_device *pdev)
|
static int tegra_spi_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct spi_master *master = dev_get_drvdata(&pdev->dev);
|
struct spi_master *master = platform_get_drvdata(pdev);
|
||||||
struct tegra_spi_data *tspi = spi_master_get_devdata(master);
|
struct tegra_spi_data *tspi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
free_irq(tspi->irq, tspi);
|
free_irq(tspi->irq, tspi);
|
||||||
|
|
|
@ -480,7 +480,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
|
||||||
master->num_chipselect = MAX_CHIP_SELECT;
|
master->num_chipselect = MAX_CHIP_SELECT;
|
||||||
master->bus_num = -1;
|
master->bus_num = -1;
|
||||||
|
|
||||||
dev_set_drvdata(&pdev->dev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
tsd = spi_master_get_devdata(master);
|
tsd = spi_master_get_devdata(master);
|
||||||
tsd->master = master;
|
tsd->master = master;
|
||||||
tsd->dev = &pdev->dev;
|
tsd->dev = &pdev->dev;
|
||||||
|
@ -555,7 +555,7 @@ exit_free_master:
|
||||||
|
|
||||||
static int tegra_sflash_remove(struct platform_device *pdev)
|
static int tegra_sflash_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct spi_master *master = dev_get_drvdata(&pdev->dev);
|
struct spi_master *master = platform_get_drvdata(pdev);
|
||||||
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
|
struct tegra_sflash_data *tsd = spi_master_get_devdata(master);
|
||||||
|
|
||||||
free_irq(tsd->irq, tsd);
|
free_irq(tsd->irq, tsd);
|
||||||
|
|
|
@ -1089,7 +1089,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
|
||||||
master->num_chipselect = MAX_CHIP_SELECT;
|
master->num_chipselect = MAX_CHIP_SELECT;
|
||||||
master->bus_num = -1;
|
master->bus_num = -1;
|
||||||
|
|
||||||
dev_set_drvdata(&pdev->dev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
tspi = spi_master_get_devdata(master);
|
tspi = spi_master_get_devdata(master);
|
||||||
tspi->master = master;
|
tspi->master = master;
|
||||||
tspi->dev = &pdev->dev;
|
tspi->dev = &pdev->dev;
|
||||||
|
@ -1193,7 +1193,7 @@ exit_free_master:
|
||||||
|
|
||||||
static int tegra_slink_remove(struct platform_device *pdev)
|
static int tegra_slink_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct spi_master *master = dev_get_drvdata(&pdev->dev);
|
struct spi_master *master = platform_get_drvdata(pdev);
|
||||||
struct tegra_slink_data *tspi = spi_master_get_devdata(master);
|
struct tegra_slink_data *tspi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
free_irq(tspi->irq, tspi);
|
free_irq(tspi->irq, tspi);
|
||||||
|
|
|
@ -237,14 +237,6 @@ static void ti_ssp_spi_work(struct work_struct *work)
|
||||||
spin_unlock(&hw->lock);
|
spin_unlock(&hw->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ti_ssp_spi_setup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
if (spi->bits_per_word > 32)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
|
static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
|
||||||
{
|
{
|
||||||
struct ti_ssp_spi *hw;
|
struct ti_ssp_spi *hw;
|
||||||
|
@ -269,12 +261,6 @@ static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
|
||||||
dev_err(&spi->dev, "invalid xfer, full duplex\n");
|
dev_err(&spi->dev, "invalid xfer, full duplex\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->bits_per_word > 32) {
|
|
||||||
dev_err(&spi->dev, "invalid xfer width %d\n",
|
|
||||||
t->bits_per_word);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&hw->lock);
|
spin_lock(&hw->lock);
|
||||||
|
@ -337,8 +323,8 @@ static int ti_ssp_spi_probe(struct platform_device *pdev)
|
||||||
master->bus_num = pdev->id;
|
master->bus_num = pdev->id;
|
||||||
master->num_chipselect = pdata->num_cs;
|
master->num_chipselect = pdata->num_cs;
|
||||||
master->mode_bits = MODE_BITS;
|
master->mode_bits = MODE_BITS;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
|
||||||
master->flags = SPI_MASTER_HALF_DUPLEX;
|
master->flags = SPI_MASTER_HALF_DUPLEX;
|
||||||
master->setup = ti_ssp_spi_setup;
|
|
||||||
master->transfer = ti_ssp_spi_transfer;
|
master->transfer = ti_ssp_spi_transfer;
|
||||||
|
|
||||||
error = spi_register_master(master);
|
error = spi_register_master(master);
|
||||||
|
|
|
@ -367,7 +367,7 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id)
|
||||||
|
|
||||||
if (reg_spsr_val & SPSR_ORF_BIT) {
|
if (reg_spsr_val & SPSR_ORF_BIT) {
|
||||||
dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__);
|
dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__);
|
||||||
if (data->current_msg->complete != 0) {
|
if (data->current_msg->complete) {
|
||||||
data->transfer_complete = true;
|
data->transfer_complete = true;
|
||||||
data->current_msg->status = -EIO;
|
data->current_msg->status = -EIO;
|
||||||
data->current_msg->complete(data->current_msg->context);
|
data->current_msg->complete(data->current_msg->context);
|
||||||
|
@ -472,11 +472,6 @@ static int pch_spi_setup(struct spi_device *pspi)
|
||||||
dev_dbg(&pspi->dev, "%s 8 bits per word\n", __func__);
|
dev_dbg(&pspi->dev, "%s 8 bits per word\n", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pspi->bits_per_word != 8) && (pspi->bits_per_word != 16)) {
|
|
||||||
dev_err(&pspi->dev, "%s Invalid bits per word\n", __func__);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check baud rate setting */
|
/* Check baud rate setting */
|
||||||
/* if baud rate of chip is greater than
|
/* if baud rate of chip is greater than
|
||||||
max we can support,return error */
|
max we can support,return error */
|
||||||
|
@ -537,17 +532,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
|
||||||
/* if baud rate has been specified validate the same */
|
/* if baud rate has been specified validate the same */
|
||||||
if (transfer->speed_hz > PCH_MAX_BAUDRATE)
|
if (transfer->speed_hz > PCH_MAX_BAUDRATE)
|
||||||
transfer->speed_hz = PCH_MAX_BAUDRATE;
|
transfer->speed_hz = PCH_MAX_BAUDRATE;
|
||||||
|
|
||||||
/* if bits per word has been specified validate the same */
|
|
||||||
if (transfer->bits_per_word) {
|
|
||||||
if ((transfer->bits_per_word != 8)
|
|
||||||
&& (transfer->bits_per_word != 16)) {
|
|
||||||
retval = -EINVAL;
|
|
||||||
dev_err(&pspi->dev,
|
|
||||||
"%s Invalid bits per word\n", __func__);
|
|
||||||
goto err_return_spinlock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&data->lock, flags);
|
spin_unlock_irqrestore(&data->lock, flags);
|
||||||
|
|
||||||
|
@ -659,7 +643,7 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw)
|
||||||
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
|
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
|
||||||
pmsg->status = -ENOMEM;
|
pmsg->status = -ENOMEM;
|
||||||
|
|
||||||
if (pmsg->complete != 0)
|
if (pmsg->complete)
|
||||||
pmsg->complete(pmsg->context);
|
pmsg->complete(pmsg->context);
|
||||||
|
|
||||||
/* delete from queue */
|
/* delete from queue */
|
||||||
|
@ -709,7 +693,7 @@ static void pch_spi_nomore_transfer(struct pch_spi_data *data)
|
||||||
* [To the spi core..indicating end of transfer] */
|
* [To the spi core..indicating end of transfer] */
|
||||||
data->current_msg->status = 0;
|
data->current_msg->status = 0;
|
||||||
|
|
||||||
if (data->current_msg->complete != 0) {
|
if (data->current_msg->complete) {
|
||||||
dev_dbg(&data->master->dev,
|
dev_dbg(&data->master->dev,
|
||||||
"%s:Invoking callback of SPI core\n", __func__);
|
"%s:Invoking callback of SPI core\n", __func__);
|
||||||
data->current_msg->complete(data->current_msg->context);
|
data->current_msg->complete(data->current_msg->context);
|
||||||
|
@ -1202,7 +1186,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
|
||||||
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
|
list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) {
|
||||||
pmsg->status = -EIO;
|
pmsg->status = -EIO;
|
||||||
|
|
||||||
if (pmsg->complete != 0) {
|
if (pmsg->complete) {
|
||||||
spin_unlock(&data->lock);
|
spin_unlock(&data->lock);
|
||||||
pmsg->complete(pmsg->context);
|
pmsg->complete(pmsg->context);
|
||||||
spin_lock(&data->lock);
|
spin_lock(&data->lock);
|
||||||
|
@ -1442,6 +1426,7 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
|
||||||
master->setup = pch_spi_setup;
|
master->setup = pch_spi_setup;
|
||||||
master->transfer = pch_spi_transfer;
|
master->transfer = pch_spi_transfer;
|
||||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||||
|
|
||||||
data->board_dat = board_dat;
|
data->board_dat = board_dat;
|
||||||
data->plat_dev = plat_dev;
|
data->plat_dev = plat_dev;
|
||||||
|
|
|
@ -116,17 +116,12 @@ static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
|
||||||
static int txx9spi_setup(struct spi_device *spi)
|
static int txx9spi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct txx9spi *c = spi_master_get_devdata(spi->master);
|
struct txx9spi *c = spi_master_get_devdata(spi->master);
|
||||||
u8 bits_per_word;
|
|
||||||
|
|
||||||
if (!spi->max_speed_hz
|
if (!spi->max_speed_hz
|
||||||
|| spi->max_speed_hz > c->max_speed_hz
|
|| spi->max_speed_hz > c->max_speed_hz
|
||||||
|| spi->max_speed_hz < c->min_speed_hz)
|
|| spi->max_speed_hz < c->min_speed_hz)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
bits_per_word = spi->bits_per_word;
|
|
||||||
if (bits_per_word != 8 && bits_per_word != 16)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (gpio_direction_output(spi->chip_select,
|
if (gpio_direction_output(spi->chip_select,
|
||||||
!(spi->mode & SPI_CS_HIGH))) {
|
!(spi->mode & SPI_CS_HIGH))) {
|
||||||
dev_err(&spi->dev, "Cannot setup GPIO for chipselect.\n");
|
dev_err(&spi->dev, "Cannot setup GPIO for chipselect.\n");
|
||||||
|
@ -319,8 +314,6 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
|
||||||
|
|
||||||
if (!t->tx_buf && !t->rx_buf && t->len)
|
if (!t->tx_buf && !t->rx_buf && t->len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (bits_per_word != 8 && bits_per_word != 16)
|
|
||||||
return -EINVAL;
|
|
||||||
if (t->len & ((bits_per_word >> 3) - 1))
|
if (t->len & ((bits_per_word >> 3) - 1))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
|
if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
|
||||||
|
@ -411,6 +404,7 @@ static int txx9spi_probe(struct platform_device *dev)
|
||||||
master->setup = txx9spi_setup;
|
master->setup = txx9spi_setup;
|
||||||
master->transfer = txx9spi_transfer;
|
master->transfer = txx9spi_transfer;
|
||||||
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
|
master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
|
||||||
|
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
|
||||||
|
|
||||||
ret = spi_register_master(master);
|
ret = spi_register_master(master);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -425,7 +419,6 @@ exit:
|
||||||
clk_disable(c->clk);
|
clk_disable(c->clk);
|
||||||
clk_put(c->clk);
|
clk_put(c->clk);
|
||||||
}
|
}
|
||||||
platform_set_drvdata(dev, NULL);
|
|
||||||
spi_master_put(master);
|
spi_master_put(master);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -436,7 +429,6 @@ static int txx9spi_remove(struct platform_device *dev)
|
||||||
struct txx9spi *c = spi_master_get_devdata(master);
|
struct txx9spi *c = spi_master_get_devdata(master);
|
||||||
|
|
||||||
spi_unregister_master(master);
|
spi_unregister_master(master);
|
||||||
platform_set_drvdata(dev, NULL);
|
|
||||||
destroy_workqueue(c->workqueue);
|
destroy_workqueue(c->workqueue);
|
||||||
clk_disable(c->clk);
|
clk_disable(c->clk);
|
||||||
clk_put(c->clk);
|
clk_put(c->clk);
|
||||||
|
|
|
@ -76,7 +76,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
|
||||||
{
|
{
|
||||||
unsigned int speed;
|
unsigned int speed;
|
||||||
|
|
||||||
if ((t->bits_per_word && t->bits_per_word != 8) || t->len > 62)
|
if (t->len > 62)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
|
speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
|
||||||
|
@ -209,14 +209,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spi_xcomm_setup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
if (spi->bits_per_word != 8)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int spi_xcomm_probe(struct i2c_client *i2c,
|
static int spi_xcomm_probe(struct i2c_client *i2c,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
|
@ -233,8 +225,8 @@ static int spi_xcomm_probe(struct i2c_client *i2c,
|
||||||
|
|
||||||
master->num_chipselect = 16;
|
master->num_chipselect = 16;
|
||||||
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_3WIRE;
|
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_3WIRE;
|
||||||
|
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||||
master->flags = SPI_MASTER_HALF_DUPLEX;
|
master->flags = SPI_MASTER_HALF_DUPLEX;
|
||||||
master->setup = spi_xcomm_setup;
|
|
||||||
master->transfer_one_message = spi_xcomm_transfer_one;
|
master->transfer_one_message = spi_xcomm_transfer_one;
|
||||||
master->dev.of_node = i2c->dev.of_node;
|
master->dev.of_node = i2c->dev.of_node;
|
||||||
i2c_set_clientdata(i2c, master);
|
i2c_set_clientdata(i2c, master);
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
*/
|
*/
|
||||||
#define XSPI_CR_OFFSET 0x60 /* Control Register */
|
#define XSPI_CR_OFFSET 0x60 /* Control Register */
|
||||||
|
|
||||||
|
#define XSPI_CR_LOOP 0x01
|
||||||
#define XSPI_CR_ENABLE 0x02
|
#define XSPI_CR_ENABLE 0x02
|
||||||
#define XSPI_CR_MASTER_MODE 0x04
|
#define XSPI_CR_MASTER_MODE 0x04
|
||||||
#define XSPI_CR_CPOL 0x08
|
#define XSPI_CR_CPOL 0x08
|
||||||
|
@ -232,21 +233,6 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xilinx_spi_setup(struct spi_device *spi)
|
|
||||||
{
|
|
||||||
/* always return 0, we can not check the number of bits.
|
|
||||||
* There are cases when SPI setup is called before any driver is
|
|
||||||
* there, in that case the SPI core defaults to 8 bits, which we
|
|
||||||
* do not support in some cases. But if we return an error, the
|
|
||||||
* SPI device would not be registered and no driver can get hold of it
|
|
||||||
* When the driver is there, it will call SPI setup again with the
|
|
||||||
* correct number of bits per transfer.
|
|
||||||
* If a driver setups with the wrong bit number, it will fail when
|
|
||||||
* it tries to do a transfer
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
|
static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
|
||||||
{
|
{
|
||||||
u8 sr;
|
u8 sr;
|
||||||
|
@ -315,7 +301,7 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See if there is more data to send */
|
/* See if there is more data to send */
|
||||||
if (!xspi->remaining_bytes > 0)
|
if (xspi->remaining_bytes <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,11 +341,12 @@ static const struct of_device_id xilinx_spi_of_match[] = {
|
||||||
MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
|
MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
|
||||||
|
|
||||||
struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
|
struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
|
||||||
u32 irq, s16 bus_num, int num_cs, int little_endian, int bits_per_word)
|
u32 irq, s16 bus_num, int num_cs, int bits_per_word)
|
||||||
{
|
{
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
struct xilinx_spi *xspi;
|
struct xilinx_spi *xspi;
|
||||||
int ret;
|
int ret;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
|
master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
|
||||||
if (!master)
|
if (!master)
|
||||||
|
@ -373,7 +360,6 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
|
||||||
xspi->bitbang.chipselect = xilinx_spi_chipselect;
|
xspi->bitbang.chipselect = xilinx_spi_chipselect;
|
||||||
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
|
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
|
||||||
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
|
xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
|
||||||
xspi->bitbang.master->setup = xilinx_spi_setup;
|
|
||||||
init_completion(&xspi->done);
|
init_completion(&xspi->done);
|
||||||
|
|
||||||
if (!request_mem_region(mem->start, resource_size(mem),
|
if (!request_mem_region(mem->start, resource_size(mem),
|
||||||
|
@ -392,13 +378,25 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
|
||||||
|
|
||||||
xspi->mem = *mem;
|
xspi->mem = *mem;
|
||||||
xspi->irq = irq;
|
xspi->irq = irq;
|
||||||
if (little_endian) {
|
|
||||||
|
/*
|
||||||
|
* Detect endianess on the IP via loop bit in CR. Detection
|
||||||
|
* must be done before reset is sent because incorrect reset
|
||||||
|
* value generates error interrupt.
|
||||||
|
* Setup little endian helper functions first and try to use them
|
||||||
|
* and check if bit was correctly setup or not.
|
||||||
|
*/
|
||||||
xspi->read_fn = xspi_read32;
|
xspi->read_fn = xspi_read32;
|
||||||
xspi->write_fn = xspi_write32;
|
xspi->write_fn = xspi_write32;
|
||||||
} else {
|
|
||||||
|
xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET);
|
||||||
|
tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
|
||||||
|
tmp &= XSPI_CR_LOOP;
|
||||||
|
if (tmp != XSPI_CR_LOOP) {
|
||||||
xspi->read_fn = xspi_read32_be;
|
xspi->read_fn = xspi_read32_be;
|
||||||
xspi->write_fn = xspi_write32_be;
|
xspi->write_fn = xspi_write32_be;
|
||||||
}
|
}
|
||||||
|
|
||||||
xspi->bits_per_word = bits_per_word;
|
xspi->bits_per_word = bits_per_word;
|
||||||
if (xspi->bits_per_word == 8) {
|
if (xspi->bits_per_word == 8) {
|
||||||
xspi->tx_fn = xspi_tx8;
|
xspi->tx_fn = xspi_tx8;
|
||||||
|
@ -462,14 +460,13 @@ static int xilinx_spi_probe(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
struct xspi_platform_data *pdata;
|
struct xspi_platform_data *pdata;
|
||||||
struct resource *r;
|
struct resource *r;
|
||||||
int irq, num_cs = 0, little_endian = 0, bits_per_word = 8;
|
int irq, num_cs = 0, bits_per_word = 8;
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
u8 i;
|
u8 i;
|
||||||
|
|
||||||
pdata = dev->dev.platform_data;
|
pdata = dev->dev.platform_data;
|
||||||
if (pdata) {
|
if (pdata) {
|
||||||
num_cs = pdata->num_chipselect;
|
num_cs = pdata->num_chipselect;
|
||||||
little_endian = pdata->little_endian;
|
|
||||||
bits_per_word = pdata->bits_per_word;
|
bits_per_word = pdata->bits_per_word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,7 +498,7 @@ static int xilinx_spi_probe(struct platform_device *dev)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
|
master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
|
||||||
little_endian, bits_per_word);
|
bits_per_word);
|
||||||
if (!master)
|
if (!master)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
@ -517,7 +514,6 @@ static int xilinx_spi_probe(struct platform_device *dev)
|
||||||
static int xilinx_spi_remove(struct platform_device *dev)
|
static int xilinx_spi_remove(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
xilinx_spi_deinit(platform_get_drvdata(dev));
|
xilinx_spi_deinit(platform_get_drvdata(dev));
|
||||||
platform_set_drvdata(dev, 0);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -308,6 +308,9 @@ struct spi_master {
|
||||||
|
|
||||||
/* bitmask of supported bits_per_word for transfers */
|
/* bitmask of supported bits_per_word for transfers */
|
||||||
u32 bits_per_word_mask;
|
u32 bits_per_word_mask;
|
||||||
|
#define SPI_BPW_MASK(bits) BIT((bits) - 1)
|
||||||
|
#define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0UL : (BIT(bits) - 1))
|
||||||
|
#define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1))
|
||||||
|
|
||||||
/* other constraints relevant to this driver */
|
/* other constraints relevant to this driver */
|
||||||
u16 flags;
|
u16 flags;
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
*/
|
*/
|
||||||
struct xspi_platform_data {
|
struct xspi_platform_data {
|
||||||
u16 num_chipselect;
|
u16 num_chipselect;
|
||||||
bool little_endian;
|
|
||||||
u8 bits_per_word;
|
u8 bits_per_word;
|
||||||
struct spi_board_info *devices;
|
struct spi_board_info *devices;
|
||||||
u8 num_devices;
|
u8 num_devices;
|
||||||
|
|
Loading…
Reference in a new issue