diff options
Diffstat (limited to 'drivers/spi/spi-davinci.c')
| -rw-r--r-- | drivers/spi/spi-davinci.c | 119 | 
1 files changed, 103 insertions, 16 deletions
| diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 13661e129d96..8234d2259722 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -28,6 +28,8 @@  #include <linux/dmaengine.h>  #include <linux/dma-mapping.h>  #include <linux/edma.h> +#include <linux/of.h> +#include <linux/of_device.h>  #include <linux/spi/spi.h>  #include <linux/spi/spi_bitbang.h>  #include <linux/slab.h> @@ -135,7 +137,7 @@ struct davinci_spi {  	int			dma_rx_chnum;  	int			dma_tx_chnum; -	struct davinci_spi_platform_data *pdata; +	struct davinci_spi_platform_data pdata;  	void			(*get_rx)(u32 rx_data, struct davinci_spi *);  	u32			(*get_tx)(struct davinci_spi *); @@ -213,7 +215,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)  	bool gpio_chipsel = false;  	dspi = spi_master_get_devdata(spi->master); -	pdata = dspi->pdata; +	pdata = &dspi->pdata;  	if (pdata->chip_sel && chip_sel < pdata->num_chipselect &&  				pdata->chip_sel[chip_sel] != SPI_INTERN_CS) @@ -392,7 +394,7 @@ static int davinci_spi_setup(struct spi_device *spi)  	struct davinci_spi_platform_data *pdata;  	dspi = spi_master_get_devdata(spi->master); -	pdata = dspi->pdata; +	pdata = &dspi->pdata;  	/* if bits per word length is zero then set it default 8 */  	if (!spi->bits_per_word) @@ -534,7 +536,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)  	struct scatterlist sg_rx, sg_tx;  	dspi = spi_master_get_devdata(spi->master); -	pdata = dspi->pdata; +	pdata = &dspi->pdata;  	spicfg = (struct davinci_spi_config *)spi->controller_data;  	if (!spicfg)  		spicfg = &davinci_spi_default_cfg; @@ -700,6 +702,19 @@ err_alloc_dummy_buf:  }  /** + * dummy_thread_fn - dummy thread function + * @irq: IRQ number for this SPI Master + * @context_data: structure for SPI Master controller davinci_spi + * + * This is to satisfy the request_threaded_irq() API so that the irq + * handler is called in interrupt context. + */ +static irqreturn_t dummy_thread_fn(s32 irq, void *data) +{ +	return IRQ_HANDLED; +} + +/**   * davinci_spi_irq - Interrupt handler for SPI Master Controller   * @irq: IRQ number for this SPI Master   * @context_data: structure for SPI Master controller davinci_spi @@ -758,6 +773,70 @@ rx_dma_failed:  	return r;  } +#if defined(CONFIG_OF) +static const struct of_device_id davinci_spi_of_match[] = { +	{ +		.compatible = "ti,dm644x-spi", +	}, +	{ +		.compatible = "ti,da8xx-spi", +		.data = (void *)SPI_VERSION_2, +	}, +	{ }, +}; +MODULE_DEVICE_TABLE(of, davini_spi_of_match); + +/** + * spi_davinci_get_pdata - Get platform data from DTS binding + * @pdev: ptr to platform data + * @dspi: ptr to driver data + * + * Parses and populates pdata in dspi from device tree bindings. + * + * NOTE: Not all platform data params are supported currently. + */ +static int spi_davinci_get_pdata(struct platform_device *pdev, +			struct davinci_spi *dspi) +{ +	struct device_node *node = pdev->dev.of_node; +	struct davinci_spi_platform_data *pdata; +	unsigned int num_cs, intr_line = 0; +	const struct of_device_id *match; + +	pdata = &dspi->pdata; + +	pdata->version = SPI_VERSION_1; +	match = of_match_device(of_match_ptr(davinci_spi_of_match), +				&pdev->dev); +	if (!match) +		return -ENODEV; + +	/* match data has the SPI version number for SPI_VERSION_2 */ +	if (match->data == (void *)SPI_VERSION_2) +		pdata->version = SPI_VERSION_2; + +	/* +	 * default num_cs is 1 and all chipsel are internal to the chip +	 * indicated by chip_sel being NULL. GPIO based CS is not +	 * supported yet in DT bindings. +	 */ +	num_cs = 1; +	of_property_read_u32(node, "num-cs", &num_cs); +	pdata->num_chipselect = num_cs; +	of_property_read_u32(node, "ti,davinci-spi-intr-line", &intr_line); +	pdata->intr_line = intr_line; +	return 0; +} +#else +#define davinci_spi_of_match NULL +static struct davinci_spi_platform_data +	*spi_davinci_get_pdata(struct platform_device *pdev, +		struct davinci_spi *dspi) +{ +	return -ENODEV; +} +#endif +  /**   * davinci_spi_probe - probe function for SPI Master Controller   * @pdev: platform_device structure which contains plateform specific data @@ -780,12 +859,6 @@ static int davinci_spi_probe(struct platform_device *pdev)  	int i = 0, ret = 0;  	u32 spipc0; -	pdata = pdev->dev.platform_data; -	if (pdata == NULL) { -		ret = -ENODEV; -		goto err; -	} -  	master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));  	if (master == NULL) {  		ret = -ENOMEM; @@ -800,6 +873,19 @@ static int davinci_spi_probe(struct platform_device *pdev)  		goto free_master;  	} +	if (pdev->dev.platform_data) { +		pdata = pdev->dev.platform_data; +		dspi->pdata = *pdata; +	} else { +		/* update dspi pdata with that from the DT */ +		ret = spi_davinci_get_pdata(pdev, dspi); +		if (ret < 0) +			goto free_master; +	} + +	/* pdata in dspi is now updated and point pdata to that */ +	pdata = &dspi->pdata; +  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (r == NULL) {  		ret = -ENOENT; @@ -807,7 +893,6 @@ static int davinci_spi_probe(struct platform_device *pdev)  	}  	dspi->pbase = r->start; -	dspi->pdata = pdata;  	mem = request_mem_region(r->start, resource_size(r), pdev->name);  	if (mem == NULL) { @@ -827,8 +912,8 @@ static int davinci_spi_probe(struct platform_device *pdev)  		goto unmap_io;  	} -	ret = request_irq(dspi->irq, davinci_spi_irq, 0, dev_name(&pdev->dev), -									dspi); +	ret = request_threaded_irq(dspi->irq, davinci_spi_irq, dummy_thread_fn, +				 0, dev_name(&pdev->dev), dspi);  	if (ret)  		goto unmap_io; @@ -843,8 +928,9 @@ static int davinci_spi_probe(struct platform_device *pdev)  		ret = -ENODEV;  		goto put_master;  	} -	clk_enable(dspi->clk); +	clk_prepare_enable(dspi->clk); +	master->dev.of_node = pdev->dev.of_node;  	master->bus_num = pdev->id;  	master->num_chipselect = pdata->num_chipselect;  	master->setup = davinci_spi_setup; @@ -927,7 +1013,7 @@ free_dma:  	dma_release_channel(dspi->dma_rx);  	dma_release_channel(dspi->dma_tx);  free_clk: -	clk_disable(dspi->clk); +	clk_disable_unprepare(dspi->clk);  	clk_put(dspi->clk);  put_master:  	spi_master_put(master); @@ -963,7 +1049,7 @@ static int davinci_spi_remove(struct platform_device *pdev)  	spi_bitbang_stop(&dspi->bitbang); -	clk_disable(dspi->clk); +	clk_disable_unprepare(dspi->clk);  	clk_put(dspi->clk);  	spi_master_put(master);  	free_irq(dspi->irq, dspi); @@ -978,6 +1064,7 @@ static struct platform_driver davinci_spi_driver = {  	.driver = {  		.name = "spi_davinci",  		.owner = THIS_MODULE, +		.of_match_table = davinci_spi_of_match,  	},  	.probe = davinci_spi_probe,  	.remove = davinci_spi_remove, |