VENDOR: Marvell: abox_edge: Enable SPI controller driver

1. Enable Marvell SPI controller and MTD m25p80 driver in kernel config
2. Add SPI pin configuration in dts file
3. Support setting the SPI controller clock dynamically
4. Use GPIO to control the #CS signal of SPI

BUG: 27844484
Change-Id: I3691f37e869dc43599417ed734ea9b9dd4db2944
diff --git a/arch/arm/configs/abox_edge_defconfig b/arch/arm/configs/abox_edge_defconfig
index 30eacdc..2dc9365 100755
--- a/arch/arm/configs/abox_edge_defconfig
+++ b/arch/arm/configs/abox_edge_defconfig
@@ -316,6 +316,7 @@
 # CONFIG_GPIO_PCA953X is not set
 # CONFIG_KEYBOARD_GPIO_POLLED is not set
 # CONFIG_MACH_TAVOREVB is not set
+CONFIG_PXA_SSP=y
 
 #
 # Marvell PXA168/910/MMP2 Implmentations
@@ -1046,6 +1047,7 @@
 # CONFIG_HAVE_CPU_AUTOPROBE is not set
 CONFIG_REGMAP=y
 CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_SPI=y
 CONFIG_REGMAP_MMIO=y
 CONFIG_REGMAP_IRQ=y
 CONFIG_DMA_SHARED_BUFFER=y
@@ -1068,7 +1070,14 @@
 #
 # CONFIG_ARM_CCI is not set
 # CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+CONFIG_MTD_M25P80=y
 CONFIG_DTC=y
 CONFIG_OF=y
 
@@ -1083,6 +1092,7 @@
 CONFIG_OF_IRQ=y
 CONFIG_OF_NET=y
 CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
 CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
@@ -1307,6 +1317,7 @@
 CONFIG_NET_VENDOR_MICREL=y
 # CONFIG_KS8842 is not set
 # CONFIG_KS8851_MLL is not set
+CONFIG_NET_VENDOR_MICROCHIP=y
 CONFIG_NET_VENDOR_NATSEMI=y
 CONFIG_NET_VENDOR_8390=y
 # CONFIG_AX88796 is not set
@@ -1647,7 +1658,11 @@
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_SPI is not set
+CONFIG_SPI=y
+CONFIG_SPI_DEBUG=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_PXA2XX_DMA=y
+CONFIG_SPI_PXA2XX=y
 # CONFIG_HSI is not set
 
 #
@@ -2238,6 +2253,7 @@
 CONFIG_MMP_DISP=y
 CONFIG_MMP_DISP_CONTROLLER=y
 CONFIG_MMP_DISP_DFC=y
+CONFIG_MMP_DISP_SPI=y
 # CONFIG_MMP_VIRTUAL_RESOLUTION is not set
 # CONFIG_MMP_PANEL_HX8394_IPS3P5071 is not set
 CONFIG_MMP_PANEL_R63311=y
@@ -2312,6 +2328,7 @@
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
 CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
 CONFIG_SND_USB=y
 CONFIG_SND_USB_AUDIO=y
 # CONFIG_SND_USB_UA101 is not set
diff --git a/arch/arm64/boot/dts/pxa1908-board-common.dtsi b/arch/arm64/boot/dts/pxa1908-board-common.dtsi
index 5c76d33..2c0c546 100644
--- a/arch/arm64/boot/dts/pxa1908-board-common.dtsi
+++ b/arch/arm64/boot/dts/pxa1908-board-common.dtsi
@@ -407,6 +407,7 @@
 					&range 55 55 0	/* GPIO0 ~ GPIO54 */
 					&range 110 32 0 /* GPIO67 ~ GPIO98 */
 					&range 52 1 0	/* GPIO124 */
+					&range 6 1 0	/* GPIO65 */
 				>;
 				pinctrl-names = "default";
 				pinctrl-0 = <&mfp_pins_group_0 &mfp_pins_group_1>;
@@ -426,10 +427,6 @@
 				mfp_pins_group_0: mfp_pins_group_0 {
 					pinctrl-single,pins = <
 						/* DF_IO8 AF0 */
-						DF_IO9 AF0
-						DF_IO10 AF0
-						DF_IO11 AF0
-						DF_IO12 AF0
 						DF_IO13 AF0
 						DF_IO15 AF0
 					>;
@@ -650,21 +647,21 @@
 				};
 
 				spi0_pmx_func: spi0_pmx_func {
-				   pinctrl-single,pins = <
-					   GPIO33 AF2 /* GPIO33 SSP0_CLK */
-					   GPIO34 AF2 /* GPIO34 SSP0_FRM */
-					   GPIO35 AF2 /* GPIO35 SSP0_RX */
-					   GPIO36 AF2 /* GPIO36 SSP0_TX */
+					pinctrl-single,pins = <
+						GPIO33 AF2 /* GPIO33 SSP0_CLK */
+						GPIO34 AF2 /* GPIO34 SSP0_FRM */
+						GPIO35 AF2 /* GPIO35 SSP0_RX */
+						GPIO36 AF2 /* GPIO36 SSP0_TX */
 					>;
 					MFP_DEFAULT;
 				};
 
-				spi1_pmx_func: spi1_pmx_func {
-				   pinctrl-single,pins = <
-					   DF_IO9 AF2  /* GPIO66 SSP2_CLK */
-					   DF_IO10 AF2 /* GPIO65 SSP2_FRM */
-					   DF_IO11 AF2 /* GPIO64 SSP2_TX */
-					   DF_IO12 AF2 /* GPIO63 SSP2_RX */
+				spi2_pmx_func: spi2_pmx_func {
+					pinctrl-single,pins = <
+						DF_IO9 AF2 /* GPIO66 SSP2_CLK */
+						DF_IO10 AF1 /* GPIO65 SSP2_FRM */
+						DF_IO11 AF2 /* GPIO64 SSP2_TX */
+						DF_IO12 AF2 /* GPIO63 SSP2_RX */
 					>;
 					MFP_DEFAULT;
 				};
@@ -1065,6 +1062,37 @@
 				};
 			};
 
+			spi_0: ssp@d401b000 {
+				status = "disabled";
+				pinctrl-names = "default";
+				pinctrl-0 = <&spi0_pmx_func>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				spidev {
+					spi-max-frequency = <52000000>;
+					reg = <0>;
+					compatible = "rohm,dh2228fv";
+					status = "okay";
+				};
+			};
+
+			spi_2: ssp@d401c000 {
+				status = "okay";
+				pinctrl-names = "default";
+				pinctrl-0 = <&spi2_pmx_func>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				flash: m25p80@0 {
+					#address-cells = <1>;
+					#size-cells = <1>;
+					compatible = "sst,sst25wf040b";
+					spi-max-frequency = <40000000>;
+					reg = <0>;
+				};
+			};
+
 			/* SSPA port 0 */
 			sspa0: sspa@d128dc00 {
 				pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/pxa1908.dtsi b/arch/arm64/boot/dts/pxa1908.dtsi
index dd9a824..987bff7 100644
--- a/arch/arm64/boot/dts/pxa1908.dtsi
+++ b/arch/arm64/boot/dts/pxa1908.dtsi
@@ -601,7 +601,7 @@
 
 				gcb2: gpio@d4019008 {
 					reg-offset = <0x8>;
-					gpio-ranges = <&pmx 3 110 29>;
+					gpio-ranges = <&pmx 1 6 1  &pmx 3 110 29>;
 				};
 
 				gcb3: gpio@d4019100 {
@@ -633,6 +633,37 @@
 				status = "disabled";
 			};
 
+			spi_0: ssp@d401b000 {
+				compatible = "marvell,pxa910-spi";
+				marvell,ssp-enhancement;
+				reg = <0xd401b000 0x90>;
+				ssp-id = <0>;
+				interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>;
+				/* dma engineer, DRCMR offset, user_do_qos */
+				dmas = <&pdma0 52 1
+					&pdma0 53 1>;
+				dma-names = "rx", "tx";
+				lpm-qos = <PM_QOS_CPUIDLE_BLOCK_AXI>;
+				clocks = <&soc_clocks PXA1U88_CLK_SSP0>;
+				status = "disabled";
+			};
+
+			spi_2: ssp@d401c000 {
+				compatible = "marvell,pxa910-spi";
+				marvell,ssp-enhancement;
+				marvell,ssp-nor-flash;
+				reg = <0xd401c000 0x90>;
+				ssp-id = <2>;
+				interrupts = <0 1 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&pdma0 60 1
+					&pdma0 61 1>;
+				dma-names = "rx", "tx";
+				lpm-qos = <PM_QOS_CPUIDLE_BLOCK_AXI>;
+				clocks = <&soc_clocks PXA1U88_CLK_SSP2>;
+				cs-gpios = <&gpio 65 0>;
+				status = "disabled";
+			};
+
 			sspa0: sspa@d128dc00 {
 				compatible = "mrvl,mmp-sspa-dai";
 				reg = <0xd128dc00 0x100>;
diff --git a/arch/arm64/mach/helanx-dt.c b/arch/arm64/mach/helanx-dt.c
index 2f0b5bc..80939ce 100644
--- a/arch/arm64/mach/helanx-dt.c
+++ b/arch/arm64/mach/helanx-dt.c
@@ -68,6 +68,9 @@
 	OF_DEV_AUXDATA("regulator-leds", 0, "leds-regulator",
 						&keypad_backlight),
 #endif
+#ifdef CONFIG_SPI_PXA2XX
+	OF_DEV_AUXDATA("marvell,pxa910-spi", 0xd401c000, "pxa910-ssp.2", NULL),
+#endif
 	{}
 };
 
diff --git a/drivers/clk/mmp/clk-pxa1U88.c b/drivers/clk/mmp/clk-pxa1U88.c
index 48d825b..7475a04 100644
--- a/drivers/clk/mmp/clk-pxa1U88.c
+++ b/drivers/clk/mmp/clk-pxa1U88.c
@@ -519,7 +519,7 @@
 		ARRAY_SIZE(ssp_parent_names), 0,
 		pxa_unit->apbc_base + APBC_SSP2, 4, 3, 0, NULL);
 	clk = mmp_clk_register_gate(NULL, "ssp2_clk", "ssp2_mux",
-				0,
+				CLK_SET_RATE_PARENT | CLK_SET_RATE_ENABLED,
 				pxa_unit->apbc_base + APBC_SSP2,
 				0x7, 0x3, 0x0, 0, NULL);
 	mmp_clk_add(unit, PXA1U88_CLK_SSP2, clk);
@@ -1494,7 +1494,6 @@
 	val = __raw_readl(pxa_unit->apmu_base + APMU_DVC_DFC_DEBUG);
 	val |= (1 << 5);
 	__raw_writel(val, pxa_unit->apmu_base + APMU_DVC_DFC_DEBUG);
-
 }
 
 static void __init pxa1U88_clk_init(struct device_node *np)
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index ad19139..4a7c796 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -977,6 +977,7 @@
 	{ "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1, SECT_4K | SST_WRITE) },
 	{ "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
 	{ "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
+	{ "sst25wf040b", INFO(0x621613, 0, 64 * 1024,  8, SECT_4K) },
 	{ "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
 
 	/* ST Microelectronics -- newer production may have feature updates */
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 98eca26..b37f657 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -593,8 +593,9 @@
 		return IRQ_NONE;
 
 	if (!drv_data->cur_msg) {
-
+		/* Disable SSPx port */
 		write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+		/* Disable TXFIFO/RXFIFO/RX-Timeout interrupt */
 		write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
 		if (!pxa25x_ssp_comp(drv_data))
 			write_SSTO(0, reg);
@@ -777,8 +778,10 @@
 					    SSCR2_RD_ENDIAN_16BITS;
 			bits = 32;
 			drv_data->n_bytes = 4;
-			drv_data->read = u32_reader;
-			drv_data->write = u32_writer;
+			drv_data->read = drv_data->read != null_reader ?
+				u32_reader : null_reader;
+                        drv_data->write = drv_data->write != null_writer ?
+				u32_writer : null_writer;
 
 			if (chip->enable_dma) {
 				if (pxa2xx_spi_set_dma_burst_and_threshold(chip,
@@ -802,7 +805,6 @@
 	if (pxa2xx_spi_dma_is_possible(drv_data->len))
 		drv_data->dma_mapped = pxa2xx_spi_map_dma_buffers(drv_data);
 	if (drv_data->dma_mapped) {
-
 		/* Ensure we have the correct interrupt handler */
 		drv_data->transfer_handler = pxa2xx_spi_dma_transfer;
 
@@ -829,6 +831,7 @@
 			write_SSITF(chip->lpss_tx_threshold, reg);
 	}
 
+
 	/* see if we need to reload the config registers */
 	if ((read_SSCR0(reg) != cr0)
 		|| (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
@@ -933,6 +936,7 @@
 	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
 	unsigned int clk_div;
 	uint tx_thres, tx_hi_thres, rx_thres;
+	int ret = 0;
 
 	if (is_lpss_ssp(drv_data)) {
 		tx_thres = LPSS_TX_LOTHRESH_DFLT;
@@ -961,10 +965,14 @@
 				kfree(chip);
 				return -EINVAL;
 			}
-
 			chip->frm = spi->chip_select;
-		} else
+		} else if (drv_data->ssp_nor_flash) {
+			chip->gpio_cs = spi->cs_gpio;
+			chip->gpio_cs_inverted = spi->mode & SPI_CS_HIGH;
+		}
+		else
 			chip->gpio_cs = -1;
+
 		chip->enable_dma = 0;
 		chip->timeout = TIMOUT_DFLT;
 	}
@@ -1013,8 +1021,13 @@
 		}
 	}
 
-	/* clk_div represent to Bit17-8 bits of CS0 */
+	/* clk_div represent to Bit19-8 bits of CS0 */
 	clk_div = ssp_get_clk_div(drv_data, spi->max_speed_hz);
+
+	/* Clock rate setting not in SSCR0 for Marvell SSP2 */
+	if (drv_data->ssp_nor_flash)
+		clk_set_rate(drv_data->clk, spi->max_speed_hz);
+
 	chip->speed_hz = spi->max_speed_hz;
 
 	chip->cr0 = clk_div
@@ -1030,8 +1043,12 @@
 	if (spi->mode & SPI_LOOP)
 		chip->cr1 |= SSCR1_LBM;
 
+	if (drv_data->ssp_nor_flash)
+		dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
+			clk_get_rate(drv_data->clk),
+			chip->enable_dma ? "DMA" : "PIO");
 	/* NOTE:  PXA25x_SSP _could_ use external clocking ... */
-	if (!pxa25x_ssp_comp(drv_data))
+	else if (!pxa25x_ssp_comp(drv_data))
 		dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
 			drv_data->max_clk_rate
 				/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
@@ -1042,7 +1059,6 @@
 				/ (1 + ((chip->cr0 & SSCR0_SCR(0x0ff)) >> 8)),
 			chip->enable_dma ? "DMA" : "PIO");
 
-
 	/* Enable rx fifo auto full control */
 	if (drv_data->ssp_enhancement)
 		chip->cr2 = SSCR2_RX_FULL_CTRL;
@@ -1066,7 +1082,21 @@
 	spi_set_ctldata(spi, chip);
 
 	if (drv_data->ssp_type == CE4100_SSP)
-		return 0;
+		return ret;
+
+	/* Configure SSP2_FRM as GPIO for SPI #CS */
+	if (drv_data->ssp_nor_flash && gpio_is_valid(chip->gpio_cs)) {
+		ret = gpio_request(chip->gpio_cs, dev_name(&spi->dev));
+		if (ret) {
+			dev_err(&spi->dev, "failed to request chip select GPIO%d\n",
+				 chip->gpio_cs);
+			return ret;
+		}
+
+		ret = gpio_direction_output(chip->gpio_cs,
+					!chip->gpio_cs_inverted);
+		return ret;
+	}
 
 	return setup_cs(spi, chip, chip_info);
 }
@@ -1228,6 +1258,11 @@
 	/* Receive FIFO auto full ctrl enable */
 	if (of_get_property(np, "marvell,ssp-enhancement", NULL))
 		drv_data->ssp_enhancement = 1;
+
+	/* Use SSP2 port for SPI Nor flash */
+	if (of_get_property(np, "marvell,ssp-nor-flash", NULL))
+		drv_data->ssp_nor_flash = 1;
+
 	/*
 	 * the null DMA buf should malloc form DMA_ZONE
 	 * and align of DMA_ALIGNMENT
@@ -1267,7 +1302,6 @@
 		master->bus_num = bus_num;
 	drv_data->ssdr_physical = iores->start + SSDR;
 	drv_data->clk = devm_clk_get(dev, NULL);
-
 #else
 	ssp = pxa_ssp_request(pdev->id, pdev->name);
 	if (!ssp)
@@ -1356,6 +1390,11 @@
 	tasklet_init(&drv_data->pump_transfers, pump_transfers,
 		     (unsigned long)drv_data);
 
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	/* Register with the SPI framework */
 	platform_set_drvdata(pdev, drv_data);
 	status = devm_spi_register_master(&pdev->dev, master);
@@ -1364,11 +1403,6 @@
 		goto out_error_clock_enabled;
 	}
 
-	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
-	pm_runtime_use_autosuspend(&pdev->dev);
-	pm_runtime_set_active(&pdev->dev);
-	pm_runtime_enable(&pdev->dev);
-
 	return status;
 
 out_error_clock_enabled:
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index 3c9788a..7fa576a 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -98,6 +98,8 @@
 	int irq;
 	/* Support RX FIFO auto full control and endian swap */
 	unsigned int ssp_enhancement;
+	/* Use SSP2 for SPI Nor flash chip */
+	unsigned int ssp_nor_flash;
 #endif
 };