From ea08eeccae9297f7aabd2ef7f0c2517ac4549acc Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:18:26 +0000
Subject: [PATCH] write in 30M

---
 kernel/drivers/spi/spi-rockchip.c |  178 +++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 106 insertions(+), 72 deletions(-)

diff --git a/kernel/drivers/spi/spi-rockchip.c b/kernel/drivers/spi/spi-rockchip.c
index e55c5c6..3249334 100644
--- a/kernel/drivers/spi/spi-rockchip.c
+++ b/kernel/drivers/spi/spi-rockchip.c
@@ -1,22 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
  * Author: Addy Ke <addy.ke@rock-chips.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
  */
 
+#include <linux/acpi.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/dmaengine.h>
-#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
@@ -197,6 +188,7 @@
 
 	struct clk *spiclk;
 	struct clk *apb_pclk;
+	struct clk *sclk_in;
 
 	void __iomem *regs;
 	dma_addr_t dma_addr_rx;
@@ -227,8 +219,10 @@
 
 	struct pinctrl_state *high_speed_state;
 	bool slave_aborted;
-	bool gpio_requested;
 	bool cs_inactive; /* spi slave tansmition stop when cs inactive */
+	bool cs_high_supported; /* native CS supports active-high polarity */
+	struct gpio_desc *ready; /* spi slave transmission ready */
+
 	struct spi_transfer *xfer; /* Store xfer temporarily */
 	phys_addr_t base_addr_phy;
 	struct miscdevice miscdev;
@@ -296,12 +290,12 @@
 		/* Keep things powered as long as CS is asserted */
 		pm_runtime_get_sync(rs->dev);
 
-		if (gpio_is_valid(spi->cs_gpio))
+		if (spi->cs_gpiod)
 			ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, 1);
 		else
 			ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select));
 	} else {
-		if (gpio_is_valid(spi->cs_gpio))
+		if (spi->cs_gpiod)
 			ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, 1);
 		else
 			ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select));
@@ -362,7 +356,7 @@
 static void rockchip_spi_pio_reader(struct rockchip_spi *rs)
 {
 	u32 words = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR);
-	u32 rx_left = rs->rx_left > words ? rs->rx_left - words : 0;
+	u32 rx_left = (rs->rx_left > words) ? rs->rx_left - words : 0;
 
 	/* the hardware doesn't allow us to change fifo threshold
 	 * level while spi is enabled, so instead make sure to leave
@@ -484,8 +478,8 @@
 {
 	u32 i;
 
-	/* burst size: 1, 2, 4, 8 */
-	for (i = 1; i < 8; i <<= 1) {
+	/* burst size: 1, 2, 4, 8, 16 */
+	for (i = 1; i < 16; i <<= 1) {
 		if (data_len & i)
 			break;
 	}
@@ -528,7 +522,7 @@
 			.direction = DMA_MEM_TO_DEV,
 			.dst_addr = rs->dma_addr_tx,
 			.dst_addr_width = rs->n_bytes,
-			.dst_maxburst = 8,
+			.dst_maxburst = rs->fifo_len / 4,
 		};
 
 		dmaengine_slave_config(ctlr->dma_tx, &txconf);
@@ -678,7 +672,9 @@
 		 * ctlr->bits_per_word_mask, so this shouldn't
 		 * happen
 		 */
-		unreachable();
+		dev_err(rs->dev, "unknown bits per word: %d\n",
+			xfer->bits_per_word);
+		return -EINVAL;
 	}
 
 	if (xfer_mode == ROCKCHIP_SPI_DMA) {
@@ -864,8 +860,17 @@
 		ret = rockchip_spi_prepare_irq(rs, ctlr, xfer);
 	}
 
+	if (rs->ready) {
+		gpiod_set_value(rs->ready, 0);
+		udelay(1);
+		gpiod_set_value(rs->ready, 1);
+	}
+
 	if (ret > 0)
 		ret = rockchip_spi_transfer_wait(ctlr, xfer);
+
+	if (rs->ready)
+		gpiod_set_value(rs->ready, 0);
 
 	return ret;
 }
@@ -886,10 +891,13 @@
 
 static int rockchip_spi_setup(struct spi_device *spi)
 {
-
-	int ret = -EINVAL;
 	struct rockchip_spi *rs = spi_controller_get_devdata(spi->controller);
 	u32 cr0;
+
+	if (!spi->cs_gpiod && (spi->mode & SPI_CS_HIGH) && !rs->cs_high_supported) {
+		dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n");
+		return -EINVAL;
+	}
 
 	pm_runtime_get_sync(rs->dev);
 
@@ -898,44 +906,14 @@
 	cr0 |= ((spi->mode & 0x3) << CR0_SCPH_OFFSET);
 	if (spi->mode & SPI_CS_HIGH)
 		cr0 |= BIT(spi->chip_select) << CR0_SOI_OFFSET;
+	if (spi_controller_is_slave(spi->controller))
+		cr0 |= CR0_OPM_SLAVE << CR0_OPM_OFFSET;
 
 	writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
 
 	pm_runtime_put(rs->dev);
 
-	if (spi->cs_gpio == -ENOENT)
-		return 0;
-
-	if (!rs->gpio_requested && gpio_is_valid(spi->cs_gpio)) {
-		ret = gpio_request_one(spi->cs_gpio,
-				       (spi->mode & SPI_CS_HIGH) ?
-				       GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
-				       dev_name(&spi->dev));
-		if (ret)
-			dev_err(&spi->dev, "can't request chipselect gpio %d\n",
-				spi->cs_gpio);
-		else
-			rs->gpio_requested = true;
-	} else {
-		if (gpio_is_valid(spi->cs_gpio)) {
-			int mode = ((spi->mode & SPI_CS_HIGH) ? 0 : 1);
-
-			ret = gpio_direction_output(spi->cs_gpio, mode);
-			if (ret)
-				dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n",
-					spi->cs_gpio, ret);
-		}
-	}
-
-	return ret;
-}
-
-static void rockchip_spi_cleanup(struct spi_device *spi)
-{
-	struct rockchip_spi *rs = spi_controller_get_devdata(spi->controller);
-
-	if (rs->gpio_requested)
-		gpio_free(spi->cs_gpio);
+	return 0;
 }
 
 static int rockchip_spi_misc_open(struct inode *inode, struct file *filp)
@@ -999,10 +977,11 @@
 	struct spi_controller *ctlr;
 	struct resource *mem;
 	struct device_node *np = pdev->dev.of_node;
-	u32 rsd_nsecs, csm;
+	u32 rsd_nsecs, num_cs, csm;
 	bool slave_mode;
 	struct pinctrl *pinctrl = NULL;
 	const struct rockchip_spi_quirks *quirks_cfg;
+	u32 val;
 
 	slave_mode = of_property_read_bool(np, "spi-slave");
 
@@ -1016,6 +995,7 @@
 	if (!ctlr)
 		return -ENOMEM;
 
+	ctlr->rt = device_property_read_bool(&pdev->dev, "rockchip,rt");
 	platform_set_drvdata(pdev, ctlr);
 
 	rs = spi_controller_get_devdata(ctlr);
@@ -1030,17 +1010,26 @@
 	}
 	rs->base_addr_phy = mem->start;
 
-	rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk");
+	if (!has_acpi_companion(&pdev->dev))
+		rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk");
 	if (IS_ERR(rs->apb_pclk)) {
 		dev_err(&pdev->dev, "Failed to get apb_pclk\n");
 		ret = PTR_ERR(rs->apb_pclk);
 		goto err_put_ctlr;
 	}
 
-	rs->spiclk = devm_clk_get(&pdev->dev, "spiclk");
+	if (!has_acpi_companion(&pdev->dev))
+		rs->spiclk = devm_clk_get(&pdev->dev, "spiclk");
 	if (IS_ERR(rs->spiclk)) {
 		dev_err(&pdev->dev, "Failed to get spi_pclk\n");
 		ret = PTR_ERR(rs->spiclk);
+		goto err_put_ctlr;
+	}
+
+	rs->sclk_in = devm_clk_get_optional(&pdev->dev, "sclk_in");
+	if (IS_ERR(rs->sclk_in)) {
+		dev_err(&pdev->dev, "Failed to get sclk_in\n");
+		ret = PTR_ERR(rs->sclk_in);
 		goto err_put_ctlr;
 	}
 
@@ -1056,23 +1045,35 @@
 		goto err_disable_apbclk;
 	}
 
+	ret = clk_prepare_enable(rs->sclk_in);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to enable sclk_in\n");
+		goto err_disable_spiclk;
+	}
+
 	spi_enable_chip(rs, false);
 
 	ret = platform_get_irq(pdev, 0);
 	if (ret < 0)
-		goto err_disable_spiclk;
+		goto err_disable_sclk_in;
 
 	ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL,
 			IRQF_ONESHOT, dev_name(&pdev->dev), ctlr);
 	if (ret)
-		goto err_disable_spiclk;
+		goto err_disable_sclk_in;
 
 	rs->dev = &pdev->dev;
-	rs->freq = clk_get_rate(rs->spiclk);
-	rs->gpio_requested = false;
 
-	if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
-				  &rsd_nsecs)) {
+	rs->freq = clk_get_rate(rs->spiclk);
+	if (!rs->freq) {
+		ret = device_property_read_u32(&pdev->dev, "clock-frequency", &rs->freq);
+		if (ret) {
+			dev_warn(rs->dev, "Failed to get clock or clock-frequency property\n");
+			goto err_disable_sclk_in;
+		}
+	}
+
+	if (!device_property_read_u32(&pdev->dev, "rx-sample-delay-ns", &rsd_nsecs)) {
 		/* rx sample delay is expressed in parent clock cycles (max 3) */
 		u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8),
 				1000000000 >> 8);
@@ -1102,33 +1103,47 @@
 	if (!rs->fifo_len) {
 		dev_err(&pdev->dev, "Failed to get fifo length\n");
 		ret = -EINVAL;
-		goto err_disable_spiclk;
+		goto err_disable_sclk_in;
 	}
 	quirks_cfg = device_get_match_data(&pdev->dev);
 	if (quirks_cfg)
 		rs->max_baud_div_in_cpha = quirks_cfg->max_baud_div_in_cpha;
+
+	if (!device_property_read_u32(&pdev->dev, "rockchip,autosuspend-delay-ms", &val)) {
+		if (val > 0) {
+			pm_runtime_set_autosuspend_delay(&pdev->dev, val);
+			pm_runtime_use_autosuspend(&pdev->dev);
+		}
+	}
 
 	pm_runtime_set_active(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
 	ctlr->auto_runtime_pm = true;
 	ctlr->bus_num = pdev->id;
-	ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST | SPI_CS_HIGH;
+	ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST;
 	if (slave_mode) {
 		ctlr->mode_bits |= SPI_NO_CS;
 		ctlr->slave_abort = rockchip_spi_slave_abort;
 	} else {
 		ctlr->flags = SPI_MASTER_GPIO_SS;
+		ctlr->max_native_cs = ROCKCHIP_SPI_MAX_CS_NUM;
+		/*
+		 * rk spi0 has two native cs, spi1..5 one cs only
+		 * if num-cs is missing in the dts, default to 1
+		 */
+		if (device_property_read_u32(&pdev->dev, "num-cs", &num_cs))
+			num_cs = 1;
+		ctlr->num_chipselect = num_cs;
+		ctlr->use_gpio_descriptors = true;
 	}
-	ctlr->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM;
 	ctlr->dev.of_node = pdev->dev.of_node;
 	ctlr->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8) | SPI_BPW_MASK(4);
 	ctlr->min_speed_hz = rs->freq / BAUDR_SCKDV_MAX;
 	ctlr->max_speed_hz = min(rs->freq / BAUDR_SCKDV_MIN, MAX_SCLK_OUT);
 
-	ctlr->set_cs = rockchip_spi_set_cs;
 	ctlr->setup = rockchip_spi_setup;
-	ctlr->cleanup = rockchip_spi_cleanup;
+	ctlr->set_cs = rockchip_spi_set_cs;
 	ctlr->transfer_one = rockchip_spi_transfer_one;
 	ctlr->max_transfer_size = rockchip_spi_max_transfer_size;
 	ctlr->handle_err = rockchip_spi_handle_err;
@@ -1169,8 +1184,9 @@
 	}
 
 	switch (rs->version) {
-	case ROCKCHIP_SPI_VER2_TYPE1:
 	case ROCKCHIP_SPI_VER2_TYPE2:
+		rs->cs_high_supported = true;
+		ctlr->mode_bits |= SPI_CS_HIGH;
 		if (slave_mode)
 			rs->cs_inactive = true;
 		else
@@ -1178,7 +1194,11 @@
 		break;
 	default:
 		rs->cs_inactive = false;
+		break;
 	}
+	if (device_property_read_bool(&pdev->dev, "rockchip,cs-inactive-disable"))
+		rs->cs_inactive = false;
+
 	pinctrl = devm_pinctrl_get(&pdev->dev);
 	if (!IS_ERR(pinctrl)) {
 		rs->high_speed_state = pinctrl_lookup_state(pinctrl, "high_speed");
@@ -1186,6 +1206,13 @@
 			dev_warn(&pdev->dev, "no high_speed pinctrl state\n");
 			rs->high_speed_state = NULL;
 		}
+	}
+
+	rs->ready = devm_gpiod_get_optional(&pdev->dev, "ready", GPIOD_OUT_HIGH);
+	if (IS_ERR(rs->ready)) {
+		ret = dev_err_probe(&pdev->dev, PTR_ERR(rs->ready),
+				    "invalid ready-gpios property in node\n");
+		goto err_free_dma_rx;
 	}
 
 	ret = devm_spi_register_controller(&pdev->dev, ctlr);
@@ -1210,7 +1237,8 @@
 			dev_info(&pdev->dev, "register misc device %s\n", misc_name);
 	}
 
-	dev_info(rs->dev, "probed, poll=%d, rsd=%d\n", rs->poll, rs->rsd);
+	dev_info(rs->dev, "probed, poll=%d, rsd=%d, cs-inactive=%d, ready=%d\n",
+		 rs->poll, rs->rsd, rs->cs_inactive, rs->ready ? 1 : 0);
 
 	return 0;
 
@@ -1222,6 +1250,8 @@
 		dma_release_channel(ctlr->dma_tx);
 err_disable_pm_runtime:
 	pm_runtime_disable(&pdev->dev);
+err_disable_sclk_in:
+	clk_disable_unprepare(rs->sclk_in);
 err_disable_spiclk:
 	clk_disable_unprepare(rs->spiclk);
 err_disable_apbclk:
@@ -1242,6 +1272,7 @@
 
 	pm_runtime_get_sync(&pdev->dev);
 
+	clk_disable_unprepare(rs->sclk_in);
 	clk_disable_unprepare(rs->spiclk);
 	clk_disable_unprepare(rs->apb_pclk);
 
@@ -1344,15 +1375,18 @@
 		.compatible = "rockchip,px30-spi",
 		.data = &rockchip_spi_quirks_cfg,
 	},
-	{ .compatible = "rockchip,rv1108-spi", },
-	{ .compatible = "rockchip,rv1126-spi", },
 	{ .compatible = "rockchip,rk3036-spi", },
 	{ .compatible = "rockchip,rk3066-spi", },
 	{ .compatible = "rockchip,rk3188-spi", },
 	{ .compatible = "rockchip,rk3228-spi", },
 	{ .compatible = "rockchip,rk3288-spi", },
+	{ .compatible = "rockchip,rk3308-spi", },
+	{ .compatible = "rockchip,rk3328-spi", },
 	{ .compatible = "rockchip,rk3368-spi", },
 	{ .compatible = "rockchip,rk3399-spi", },
+	{ .compatible = "rockchip,rv1106-spi", },
+	{ .compatible = "rockchip,rv1108-spi", },
+	{ .compatible = "rockchip,rv1126-spi", },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);

--
Gitblit v1.6.2