ath79: add new ar934x spi driver
A new shift mode was introduced since ar934x which has a way better performance than current bitbang driver and can handle higher spi clock properly. This commit adds a new driver to make use of this new feature. This new driver has chipselect properly configured and we don't need cs-gpios hack in dts anymore. Remove them. Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
This commit is contained in:
		| @@ -211,6 +211,7 @@ CONFIG_SERIAL_AR933X_CONSOLE=y | |||||||
| CONFIG_SERIAL_AR933X_NR_UARTS=2 | CONFIG_SERIAL_AR933X_NR_UARTS=2 | ||||||
| CONFIG_SERIAL_OF_PLATFORM=y | CONFIG_SERIAL_OF_PLATFORM=y | ||||||
| CONFIG_SPI=y | CONFIG_SPI=y | ||||||
|  | CONFIG_SPI_AR934X=y | ||||||
| CONFIG_SPI_ATH79=y | CONFIG_SPI_ATH79=y | ||||||
| CONFIG_SPI_BITBANG=y | CONFIG_SPI_BITBANG=y | ||||||
| CONFIG_SPI_GPIO=y | CONFIG_SPI_GPIO=y | ||||||
|   | |||||||
| @@ -110,7 +110,6 @@ | |||||||
| 	status = "okay"; | 	status = "okay"; | ||||||
|  |  | ||||||
| 	num-cs = <2>; | 	num-cs = <2>; | ||||||
| 	cs-gpios= <0>, <0>; |  | ||||||
|  |  | ||||||
| 	flash@0 { | 	flash@0 { | ||||||
| 		#address-cells = <1>; | 		#address-cells = <1>; | ||||||
|   | |||||||
| @@ -183,11 +183,10 @@ | |||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		spi: spi@1f000000 { | 		spi: spi@1f000000 { | ||||||
| 			compatible = "qca,ar9340-spi", "qca,ar7100-spi"; | 			compatible = "qca,ar934x-spi"; | ||||||
| 			reg = <0x1f000000 0x1c>; | 			reg = <0x1f000000 0x1c>; | ||||||
|  |  | ||||||
| 			clocks = <&pll ATH79_CLK_AHB>; | 			clocks = <&pll ATH79_CLK_AHB>; | ||||||
| 			clock-names = "ahb"; |  | ||||||
|  |  | ||||||
| 			#address-cells = <1>; | 			#address-cells = <1>; | ||||||
| 			#size-cells = <0>; | 			#size-cells = <0>; | ||||||
|   | |||||||
| @@ -76,7 +76,6 @@ | |||||||
| 	status = "okay"; | 	status = "okay"; | ||||||
|  |  | ||||||
| 	num-cs = <2>; | 	num-cs = <2>; | ||||||
| 	cs-gpios = <0>, <0>; |  | ||||||
|  |  | ||||||
| 	flash@0 { | 	flash@0 { | ||||||
| 		compatible = "jedec,spi-nor"; | 		compatible = "jedec,spi-nor"; | ||||||
|   | |||||||
| @@ -201,11 +201,10 @@ | |||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		spi: spi@1f000000 { | 		spi: spi@1f000000 { | ||||||
| 			compatible = "qca,ar9530-spi", "qca,ar7100-spi"; | 			compatible = "qca,ar934x-spi"; | ||||||
| 			reg = <0x1f000000 0x10>; | 			reg = <0x1f000000 0x1c>; | ||||||
|  |  | ||||||
| 			clocks = <&pll ATH79_CLK_AHB>; | 			clocks = <&pll ATH79_CLK_AHB>; | ||||||
| 			clock-names = "ahb"; |  | ||||||
|  |  | ||||||
| 			status = "disabled"; | 			status = "disabled"; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -292,11 +292,10 @@ | |||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		spi: spi@1f000000 { | 		spi: spi@1f000000 { | ||||||
| 			compatible = "qca,ar9557-spi", "qca,ar7100-spi"; | 			compatible = "qca,ar934x-spi"; | ||||||
| 			reg = <0x1f000000 0x10>; | 			reg = <0x1f000000 0x1c>; | ||||||
|  |  | ||||||
| 			clocks = <&pll ATH79_CLK_AHB>; | 			clocks = <&pll ATH79_CLK_AHB>; | ||||||
| 			clock-names = "ahb"; |  | ||||||
|  |  | ||||||
| 			status = "disabled"; | 			status = "disabled"; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -75,7 +75,6 @@ | |||||||
| 	status = "okay"; | 	status = "okay"; | ||||||
|  |  | ||||||
| 	num-cs = <2>; | 	num-cs = <2>; | ||||||
| 	cs-gpios = <0>, <0>; |  | ||||||
|  |  | ||||||
| 	flash_nor: flash@0 { | 	flash_nor: flash@0 { | ||||||
| 		compatible = "jedec,spi-nor"; | 		compatible = "jedec,spi-nor"; | ||||||
|   | |||||||
| @@ -100,7 +100,6 @@ | |||||||
| 	status = "okay"; | 	status = "okay"; | ||||||
|  |  | ||||||
| 	num-cs = <2>; | 	num-cs = <2>; | ||||||
| 	cs-gpios = <0>, <0>; |  | ||||||
|  |  | ||||||
| 	flash@0 { | 	flash@0 { | ||||||
| 		compatible = "jedec,spi-nor"; | 		compatible = "jedec,spi-nor"; | ||||||
|   | |||||||
| @@ -215,11 +215,10 @@ | |||||||
| 		}; | 		}; | ||||||
|  |  | ||||||
| 		spi: spi@1f000000 { | 		spi: spi@1f000000 { | ||||||
| 			compatible = "qca,qca9560-spi", "qca,ar7100-spi"; | 			compatible = "qca,ar934x-spi"; | ||||||
| 			reg = <0x1f000000 0x10>; | 			reg = <0x1f000000 0x1c>; | ||||||
|  |  | ||||||
| 			clocks = <&pll ATH79_CLK_AHB>; | 			clocks = <&pll ATH79_CLK_AHB>; | ||||||
| 			clock-names = "ahb"; |  | ||||||
|  |  | ||||||
| 			status = "disabled"; | 			status = "disabled"; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,61 @@ | |||||||
|  | From 7945f929f1a77a1c8887a97ca07f87626858ff42 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||||||
|  | Date: Wed, 20 Feb 2019 11:12:39 +0000 | ||||||
|  | Subject: [PATCH] drivers: provide devm_platform_ioremap_resource() | ||||||
|  |  | ||||||
|  | There are currently 1200+ instances of using platform_get_resource() | ||||||
|  | and devm_ioremap_resource() together in the kernel tree. | ||||||
|  |  | ||||||
|  | This patch wraps these two calls in a single helper. Thanks to that | ||||||
|  | we don't have to declare a local variable for struct resource * and can | ||||||
|  | omit the redundant argument for resource type. We also have one | ||||||
|  | function call less. | ||||||
|  |  | ||||||
|  | Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||||||
|  | Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||||||
|  | Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | ||||||
|  | Signed-off-by: Linus Walleij <linus.walleij@linaro.org> | ||||||
|  | --- | ||||||
|  |  drivers/base/platform.c         | 18 ++++++++++++++++++ | ||||||
|  |  include/linux/platform_device.h |  3 +++ | ||||||
|  |  2 files changed, 21 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/drivers/base/platform.c | ||||||
|  | +++ b/drivers/base/platform.c | ||||||
|  | @@ -80,6 +80,24 @@ struct resource *platform_get_resource(s | ||||||
|  |  EXPORT_SYMBOL_GPL(platform_get_resource); | ||||||
|  |   | ||||||
|  |  /** | ||||||
|  | + * devm_platform_ioremap_resource - call devm_ioremap_resource() for a platform | ||||||
|  | + *				    device | ||||||
|  | + * | ||||||
|  | + * @pdev: platform device to use both for memory resource lookup as well as | ||||||
|  | + *        resource managemend | ||||||
|  | + * @index: resource index | ||||||
|  | + */ | ||||||
|  | +void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev, | ||||||
|  | +					     unsigned int index) | ||||||
|  | +{ | ||||||
|  | +	struct resource *res; | ||||||
|  | + | ||||||
|  | +	res = platform_get_resource(pdev, IORESOURCE_MEM, index); | ||||||
|  | +	return devm_ioremap_resource(&pdev->dev, res); | ||||||
|  | +} | ||||||
|  | +EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource); | ||||||
|  | + | ||||||
|  | +/** | ||||||
|  |   * platform_get_irq - get an IRQ for a device | ||||||
|  |   * @dev: platform device | ||||||
|  |   * @num: IRQ number index | ||||||
|  | --- a/include/linux/platform_device.h | ||||||
|  | +++ b/include/linux/platform_device.h | ||||||
|  | @@ -51,6 +51,9 @@ extern struct device platform_bus; | ||||||
|  |  extern void arch_setup_pdev_archdata(struct platform_device *); | ||||||
|  |  extern struct resource *platform_get_resource(struct platform_device *, | ||||||
|  |  					      unsigned int, unsigned int); | ||||||
|  | +extern void __iomem * | ||||||
|  | +devm_platform_ioremap_resource(struct platform_device *pdev, | ||||||
|  | +			       unsigned int index); | ||||||
|  |  extern int platform_get_irq(struct platform_device *, unsigned int); | ||||||
|  |  extern int platform_irq_count(struct platform_device *); | ||||||
|  |  extern struct resource *platform_get_resource_byname(struct platform_device *, | ||||||
| @@ -0,0 +1,277 @@ | |||||||
|  | From b518f18f89dbd49fe9403a8c92230f1af59219bc Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Chuanhong Guo <gch981213@gmail.com> | ||||||
|  | Date: Wed, 5 Feb 2020 18:25:37 +0800 | ||||||
|  | Subject: [PATCH 1/2] spi: add driver for ar934x spi controller | ||||||
|  |  | ||||||
|  | This patch adds driver for SPI controller found in Qualcomm Atheros | ||||||
|  | AR934x/QCA95xx SoCs. | ||||||
|  | This controller is a superset of the already supported qca,ar7100-spi. | ||||||
|  | Besides the bit-bang mode in spi-ath79.c, this new controller added | ||||||
|  | a new "shift register" mode, allowing faster spi operations. | ||||||
|  |  | ||||||
|  | Signed-off-by: Chuanhong Guo <gch981213@gmail.com> | ||||||
|  | --- | ||||||
|  |  drivers/spi/Kconfig      |   7 ++ | ||||||
|  |  drivers/spi/Makefile     |   1 + | ||||||
|  |  drivers/spi/spi-ar934x.c | 229 +++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  3 files changed, 237 insertions(+) | ||||||
|  |  create mode 100644 drivers/spi/spi-ar934x.c | ||||||
|  |  | ||||||
|  | --- a/drivers/spi/Kconfig | ||||||
|  | +++ b/drivers/spi/Kconfig | ||||||
|  | @@ -61,6 +61,13 @@ config SPI_ALTERA | ||||||
|  |  	help | ||||||
|  |  	  This is the driver for the Altera SPI Controller. | ||||||
|  |   | ||||||
|  | +config SPI_AR934X | ||||||
|  | +	tristate "Qualcomm Atheros AR934X/QCA95XX SPI controller driver" | ||||||
|  | +	depends on ATH79 || COMPILE_TEST | ||||||
|  | +	help | ||||||
|  | +	  This enables support for the SPI controller present on the | ||||||
|  | +	  Qualcomm Atheros AR934X/QCA95XX SoCs. | ||||||
|  | + | ||||||
|  |  config SPI_ATH79 | ||||||
|  |  	tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver" | ||||||
|  |  	depends on ATH79 && GPIOLIB | ||||||
|  | --- a/drivers/spi/Makefile | ||||||
|  | +++ b/drivers/spi/Makefile | ||||||
|  | @@ -14,6 +14,7 @@ obj-$(CONFIG_SPI_LOOPBACK_TEST)		+= spi- | ||||||
|  |   | ||||||
|  |  # SPI master controller drivers (bus) | ||||||
|  |  obj-$(CONFIG_SPI_ALTERA)		+= spi-altera.o | ||||||
|  | +obj-$(CONFIG_SPI_AR934X)		+= spi-ar934x.o | ||||||
|  |  obj-$(CONFIG_SPI_ARMADA_3700)		+= spi-armada-3700.o | ||||||
|  |  obj-$(CONFIG_SPI_ATMEL)			+= spi-atmel.o | ||||||
|  |  obj-$(CONFIG_SPI_ATH79)			+= spi-ath79.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/spi/spi-ar934x.c | ||||||
|  | @@ -0,0 +1,229 @@ | ||||||
|  | +// SPDX-License-Identifier: GPL-2.0 | ||||||
|  | +// | ||||||
|  | +// SPI controller driver for Qualcomm Atheros AR934x/QCA95xx SoCs | ||||||
|  | +// | ||||||
|  | +// Copyright (C) 2020 Chuanhong Guo <gch981213@gmail.com> | ||||||
|  | +// | ||||||
|  | +// Based on spi-mt7621.c: | ||||||
|  | +// Copyright (C) 2011 Sergiy <piratfm@gmail.com> | ||||||
|  | +// Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> | ||||||
|  | +// Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name> | ||||||
|  | + | ||||||
|  | +#include <linux/clk.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/iopoll.h> | ||||||
|  | +#include <linux/kernel.h> | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/of_device.h> | ||||||
|  | +#include <linux/spi/spi.h> | ||||||
|  | + | ||||||
|  | +#define DRIVER_NAME "spi-ar934x" | ||||||
|  | + | ||||||
|  | +#define AR934X_SPI_REG_FS		0x00 | ||||||
|  | +#define AR934X_SPI_ENABLE		BIT(0) | ||||||
|  | + | ||||||
|  | +#define AR934X_SPI_REG_CTRL		0x04 | ||||||
|  | +#define AR934X_SPI_CLK_MASK		GENMASK(5, 0) | ||||||
|  | + | ||||||
|  | +#define AR934X_SPI_DATAOUT		0x10 | ||||||
|  | + | ||||||
|  | +#define AR934X_SPI_REG_SHIFT_CTRL	0x14 | ||||||
|  | +#define AR934X_SPI_SHIFT_EN		BIT(31) | ||||||
|  | +#define AR934X_SPI_SHIFT_CS(n)		BIT(28 + (n)) | ||||||
|  | +#define AR934X_SPI_SHIFT_TERM		26 | ||||||
|  | +#define AR934X_SPI_SHIFT_VAL(cs, term, count)			\ | ||||||
|  | +	(AR934X_SPI_SHIFT_EN | AR934X_SPI_SHIFT_CS(cs) |	\ | ||||||
|  | +	(term) << AR934X_SPI_SHIFT_TERM | (count)) | ||||||
|  | + | ||||||
|  | +#define AR934X_SPI_DATAIN 0x18 | ||||||
|  | + | ||||||
|  | +struct ar934x_spi { | ||||||
|  | +	struct spi_controller *ctlr; | ||||||
|  | +	void __iomem *base; | ||||||
|  | +	struct clk *clk; | ||||||
|  | +	unsigned int clk_freq; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static inline int ar934x_spi_clk_div(struct ar934x_spi *sp, unsigned int freq) | ||||||
|  | +{ | ||||||
|  | +	int div = DIV_ROUND_UP(sp->clk_freq, freq * 2) - 1; | ||||||
|  | + | ||||||
|  | +	if (div < 0) | ||||||
|  | +		return 0; | ||||||
|  | +	else if (div > AR934X_SPI_CLK_MASK) | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	else | ||||||
|  | +		return div; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ar934x_spi_setup(struct spi_device *spi) | ||||||
|  | +{ | ||||||
|  | +	struct ar934x_spi *sp = spi_controller_get_devdata(spi->master); | ||||||
|  | + | ||||||
|  | +	if ((spi->max_speed_hz == 0) || | ||||||
|  | +	    (spi->max_speed_hz > (sp->clk_freq / 2))) { | ||||||
|  | +		spi->max_speed_hz = sp->clk_freq / 2; | ||||||
|  | +	} else if (spi->max_speed_hz < (sp->clk_freq / 128)) { | ||||||
|  | +		dev_err(&spi->dev, "spi clock is too low\n"); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ar934x_spi_transfer_one_message(struct spi_controller *master, | ||||||
|  | +					   struct spi_message *m) | ||||||
|  | +{ | ||||||
|  | +	struct ar934x_spi *sp = spi_controller_get_devdata(master); | ||||||
|  | +	struct spi_transfer *t = NULL; | ||||||
|  | +	struct spi_device *spi = m->spi; | ||||||
|  | +	unsigned long trx_done, trx_cur; | ||||||
|  | +	int stat = 0; | ||||||
|  | +	u8 term = 0; | ||||||
|  | +	int div, i; | ||||||
|  | +	u32 reg; | ||||||
|  | +	const u8 *tx_buf; | ||||||
|  | +	u8 *buf; | ||||||
|  | + | ||||||
|  | +	m->actual_length = 0; | ||||||
|  | +	list_for_each_entry(t, &m->transfers, transfer_list) { | ||||||
|  | +		if (t->speed_hz) | ||||||
|  | +			div = ar934x_spi_clk_div(sp, t->speed_hz); | ||||||
|  | +		else | ||||||
|  | +			div = ar934x_spi_clk_div(sp, spi->max_speed_hz); | ||||||
|  | +		if (div < 0) { | ||||||
|  | +			stat = -EIO; | ||||||
|  | +			goto msg_done; | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  | +		reg = ioread32(sp->base + AR934X_SPI_REG_CTRL); | ||||||
|  | +		reg &= ~AR934X_SPI_CLK_MASK; | ||||||
|  | +		reg |= div; | ||||||
|  | +		iowrite32(reg, sp->base + AR934X_SPI_REG_CTRL); | ||||||
|  | +		iowrite32(0, sp->base + AR934X_SPI_DATAOUT); | ||||||
|  | + | ||||||
|  | +		for (trx_done = 0; trx_done < t->len; trx_done += 4) { | ||||||
|  | +			trx_cur = t->len - trx_done; | ||||||
|  | +			if (trx_cur > 4) | ||||||
|  | +				trx_cur = 4; | ||||||
|  | +			else if (list_is_last(&t->transfer_list, &m->transfers)) | ||||||
|  | +				term = 1; | ||||||
|  | + | ||||||
|  | +			if (t->tx_buf) { | ||||||
|  | +				tx_buf = t->tx_buf + trx_done; | ||||||
|  | +				reg = tx_buf[0]; | ||||||
|  | +				for (i = 1; i < trx_cur; i++) | ||||||
|  | +					reg = reg << 8 | tx_buf[i]; | ||||||
|  | +				iowrite32(reg, sp->base + AR934X_SPI_DATAOUT); | ||||||
|  | +			} | ||||||
|  | + | ||||||
|  | +			reg = AR934X_SPI_SHIFT_VAL(spi->chip_select, term, | ||||||
|  | +						   trx_cur * 8); | ||||||
|  | +			iowrite32(reg, sp->base + AR934X_SPI_REG_SHIFT_CTRL); | ||||||
|  | +			stat = readl_poll_timeout( | ||||||
|  | +				sp->base + AR934X_SPI_REG_SHIFT_CTRL, reg, | ||||||
|  | +				!(reg & AR934X_SPI_SHIFT_EN), 0, 5); | ||||||
|  | +			if (stat < 0) | ||||||
|  | +				goto msg_done; | ||||||
|  | + | ||||||
|  | +			if (t->rx_buf) { | ||||||
|  | +				reg = ioread32(sp->base + AR934X_SPI_DATAIN); | ||||||
|  | +				buf = t->rx_buf + trx_done; | ||||||
|  | +				for (i = 0; i < trx_cur; i++) { | ||||||
|  | +					buf[trx_cur - i - 1] = reg & 0xff; | ||||||
|  | +					reg >>= 8; | ||||||
|  | +				} | ||||||
|  | +			} | ||||||
|  | +		} | ||||||
|  | +		m->actual_length += t->len; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +msg_done: | ||||||
|  | +	m->status = stat; | ||||||
|  | +	spi_finalize_current_message(master); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct of_device_id ar934x_spi_match[] = { | ||||||
|  | +	{ .compatible = "qca,ar934x-spi" }, | ||||||
|  | +	{}, | ||||||
|  | +}; | ||||||
|  | +MODULE_DEVICE_TABLE(of, ar934x_spi_match); | ||||||
|  | + | ||||||
|  | +static int ar934x_spi_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct spi_controller *ctlr; | ||||||
|  | +	struct ar934x_spi *sp; | ||||||
|  | +	void __iomem *base; | ||||||
|  | +	struct clk *clk; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	base = devm_platform_ioremap_resource(pdev, 0); | ||||||
|  | +	if (IS_ERR(base)) | ||||||
|  | +		return PTR_ERR(base); | ||||||
|  | + | ||||||
|  | +	clk = devm_clk_get(&pdev->dev, NULL); | ||||||
|  | +	if (IS_ERR(clk)) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to get clock\n"); | ||||||
|  | +		return PTR_ERR(clk); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	ret = clk_prepare_enable(clk); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ctlr = spi_alloc_master(&pdev->dev, sizeof(*sp)); | ||||||
|  | +	if (!ctlr) { | ||||||
|  | +		dev_info(&pdev->dev, "failed to allocate spi controller\n"); | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	iowrite32(AR934X_SPI_ENABLE, base + AR934X_SPI_REG_FS); | ||||||
|  | + | ||||||
|  | +	ctlr->mode_bits = SPI_LSB_FIRST; | ||||||
|  | +	ctlr->setup = ar934x_spi_setup; | ||||||
|  | +	ctlr->transfer_one_message = ar934x_spi_transfer_one_message; | ||||||
|  | +	ctlr->bits_per_word_mask = SPI_BPW_MASK(8); | ||||||
|  | +	ctlr->dev.of_node = pdev->dev.of_node; | ||||||
|  | +	ctlr->num_chipselect = 3; | ||||||
|  | + | ||||||
|  | +	dev_set_drvdata(&pdev->dev, ctlr); | ||||||
|  | + | ||||||
|  | +	sp = spi_controller_get_devdata(ctlr); | ||||||
|  | +	sp->base = base; | ||||||
|  | +	sp->clk = clk; | ||||||
|  | +	sp->clk_freq = clk_get_rate(clk); | ||||||
|  | +	sp->ctlr = ctlr; | ||||||
|  | + | ||||||
|  | +	return devm_spi_register_controller(&pdev->dev, ctlr); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ar934x_spi_remove(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct spi_controller *ctlr; | ||||||
|  | +	struct ar934x_spi *sp; | ||||||
|  | + | ||||||
|  | +	ctlr = dev_get_drvdata(&pdev->dev); | ||||||
|  | +	sp = spi_controller_get_devdata(ctlr); | ||||||
|  | + | ||||||
|  | +	clk_disable_unprepare(sp->clk); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static struct platform_driver ar934x_spi_driver = { | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = DRIVER_NAME, | ||||||
|  | +		.of_match_table = ar934x_spi_match, | ||||||
|  | +	}, | ||||||
|  | +	.probe = ar934x_spi_probe, | ||||||
|  | +	.remove = ar934x_spi_remove, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +module_platform_driver(ar934x_spi_driver); | ||||||
|  | + | ||||||
|  | +MODULE_DESCRIPTION("SPI controller driver for Qualcomm Atheros AR934x/QCA95xx"); | ||||||
|  | +MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>"); | ||||||
|  | +MODULE_LICENSE("GPL v2"); | ||||||
|  | +MODULE_ALIAS("platform:" DRIVER_NAME); | ||||||
		Reference in New Issue
	
	Block a user
	 Chuanhong Guo
					Chuanhong Guo