Unverified Commit a6cda1f9 authored by Sunny Luo's avatar Sunny Luo Committed by Mark Brown
Browse files

spi: meson-spicc: enhance output enable feature



The SPICC controller in Meson-AXG is capable of driving the CLK/MOSI/SS
signal lines through the idle state (between two transmission operation),
which avoid the signals floating in unexpected state.

Signed-off-by: default avatarNeil Armstrong <narmstrong@baylibre.com>
Signed-off-by: default avatarYixun Lan <yixun.lan@amlogic.com>
Signed-off-by: default avatarSunny Luo <sunny.luo@amlogic.com>
Link: https://lore.kernel.org/r/20200312133131.26430-3-narmstrong@baylibre.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent b9dfb20e
Loading
Loading
Loading
Loading
+51 −2
Original line number Diff line number Diff line
@@ -9,11 +9,13 @@

#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
@@ -113,12 +115,23 @@

#define SPICC_DWADDR	0x24	/* Write Address of DMA */

#define SPICC_ENH_CTL0	0x38	/* Enhanced Feature */
#define SPICC_ENH_MOSI_OEN		BIT(25)
#define SPICC_ENH_CLK_OEN		BIT(26)
#define SPICC_ENH_CS_OEN		BIT(27)
#define SPICC_ENH_CLK_CS_DELAY_EN	BIT(28)
#define SPICC_ENH_MAIN_CLK_AO		BIT(29)

#define writel_bits_relaxed(mask, val, addr) \
	writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr)

#define SPICC_BURST_MAX	16
#define SPICC_FIFO_HALF 10

struct meson_spicc_data {
	bool				has_oen;
};

struct meson_spicc_device {
	struct spi_master		*master;
	struct platform_device		*pdev;
@@ -126,6 +139,7 @@ struct meson_spicc_device {
	struct clk			*core;
	struct spi_message		*message;
	struct spi_transfer		*xfer;
	const struct meson_spicc_data	*data;
	u8				*tx_buf;
	u8				*rx_buf;
	unsigned int			bytes_per_word;
@@ -136,6 +150,19 @@ struct meson_spicc_device {
	bool				is_last_burst;
};

static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
{
	u32 conf;

	if (!spicc->data->has_oen)
		return;

	conf = readl_relaxed(spicc->base + SPICC_ENH_CTL0) |
		SPICC_ENH_MOSI_OEN | SPICC_ENH_CLK_OEN | SPICC_ENH_CS_OEN;

	writel_relaxed(conf, spicc->base + SPICC_ENH_CTL0);
}

static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc)
{
	return !!FIELD_GET(SPICC_TF,
@@ -489,6 +516,13 @@ static int meson_spicc_probe(struct platform_device *pdev)
	spicc = spi_master_get_devdata(master);
	spicc->master = master;

	spicc->data = of_device_get_match_data(&pdev->dev);
	if (!spicc->data) {
		dev_err(&pdev->dev, "failed to get match data\n");
		ret = -EINVAL;
		goto out_master;
	}

	spicc->pdev = pdev;
	platform_set_drvdata(pdev, spicc);

@@ -548,6 +582,8 @@ static int meson_spicc_probe(struct platform_device *pdev)
	else
		master->max_speed_hz = rate >> 2;

	meson_spicc_oen_enable(spicc);

	ret = devm_spi_register_master(&pdev->dev, master);
	if (ret) {
		dev_err(&pdev->dev, "spi master registration failed\n");
@@ -577,9 +613,22 @@ static int meson_spicc_remove(struct platform_device *pdev)
	return 0;
}

static const struct meson_spicc_data meson_spicc_gx_data = {
};

static const struct meson_spicc_data meson_spicc_axg_data = {
	.has_oen		= true,
};

static const struct of_device_id meson_spicc_of_match[] = {
	{ .compatible = "amlogic,meson-gx-spicc", },
	{ .compatible = "amlogic,meson-axg-spicc", },
	{
		.compatible	= "amlogic,meson-gx-spicc",
		.data		= &meson_spicc_gx_data,
	},
	{
		.compatible = "amlogic,meson-axg-spicc",
		.data		= &meson_spicc_axg_data,
	},
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, meson_spicc_of_match);