spi: mediatek: add set_cs_timing support
this patch add set_cs_timing support for HW CS mode. Signed-off-by: leilk.liu <leilk.liu@mediatek.com> Link: https://lore.kernel.org/r/20210207030953.9297-4-leilk.liu@mediatek.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
0486d9f91d
commit
9f6e7e8d43
|
@ -287,7 +287,7 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable)
|
||||||
static void mtk_spi_prepare_transfer(struct spi_master *master,
|
static void mtk_spi_prepare_transfer(struct spi_master *master,
|
||||||
struct spi_transfer *xfer)
|
struct spi_transfer *xfer)
|
||||||
{
|
{
|
||||||
u32 spi_clk_hz, div, sck_time, cs_time, reg_val;
|
u32 spi_clk_hz, div, sck_time, reg_val;
|
||||||
struct mtk_spi *mdata = spi_master_get_devdata(master);
|
struct mtk_spi *mdata = spi_master_get_devdata(master);
|
||||||
|
|
||||||
spi_clk_hz = clk_get_rate(mdata->spi_clk);
|
spi_clk_hz = clk_get_rate(mdata->spi_clk);
|
||||||
|
@ -297,32 +297,25 @@ static void mtk_spi_prepare_transfer(struct spi_master *master,
|
||||||
div = 1;
|
div = 1;
|
||||||
|
|
||||||
sck_time = (div + 1) / 2;
|
sck_time = (div + 1) / 2;
|
||||||
cs_time = sck_time * 2;
|
|
||||||
|
|
||||||
if (mdata->dev_comp->enhance_timing) {
|
if (mdata->dev_comp->enhance_timing) {
|
||||||
reg_val = (((sck_time - 1) & 0xffff)
|
reg_val = readl(mdata->base + SPI_CFG2_REG);
|
||||||
|
reg_val &= ~(0xffff << SPI_CFG2_SCK_HIGH_OFFSET);
|
||||||
|
reg_val |= (((sck_time - 1) & 0xffff)
|
||||||
<< SPI_CFG2_SCK_HIGH_OFFSET);
|
<< SPI_CFG2_SCK_HIGH_OFFSET);
|
||||||
|
reg_val &= ~(0xffff << SPI_CFG2_SCK_LOW_OFFSET);
|
||||||
reg_val |= (((sck_time - 1) & 0xffff)
|
reg_val |= (((sck_time - 1) & 0xffff)
|
||||||
<< SPI_CFG2_SCK_LOW_OFFSET);
|
<< SPI_CFG2_SCK_LOW_OFFSET);
|
||||||
writel(reg_val, mdata->base + SPI_CFG2_REG);
|
writel(reg_val, mdata->base + SPI_CFG2_REG);
|
||||||
reg_val = (((cs_time - 1) & 0xffff)
|
|
||||||
<< SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
|
|
||||||
reg_val |= (((cs_time - 1) & 0xffff)
|
|
||||||
<< SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
|
|
||||||
writel(reg_val, mdata->base + SPI_CFG0_REG);
|
|
||||||
} else {
|
} else {
|
||||||
reg_val = (((sck_time - 1) & 0xff)
|
reg_val = readl(mdata->base + SPI_CFG0_REG);
|
||||||
|
reg_val &= ~(0xff << SPI_CFG0_SCK_HIGH_OFFSET);
|
||||||
|
reg_val |= (((sck_time - 1) & 0xff)
|
||||||
<< SPI_CFG0_SCK_HIGH_OFFSET);
|
<< SPI_CFG0_SCK_HIGH_OFFSET);
|
||||||
|
reg_val &= ~(0xff << SPI_CFG0_SCK_LOW_OFFSET);
|
||||||
reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET);
|
reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET);
|
||||||
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
|
|
||||||
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG0_CS_SETUP_OFFSET);
|
|
||||||
writel(reg_val, mdata->base + SPI_CFG0_REG);
|
writel(reg_val, mdata->base + SPI_CFG0_REG);
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_val = readl(mdata->base + SPI_CFG1_REG);
|
|
||||||
reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
|
|
||||||
reg_val |= (((cs_time - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
|
|
||||||
writel(reg_val, mdata->base + SPI_CFG1_REG);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mtk_spi_setup_packet(struct spi_master *master)
|
static void mtk_spi_setup_packet(struct spi_master *master)
|
||||||
|
@ -513,6 +506,52 @@ static bool mtk_spi_can_dma(struct spi_master *master,
|
||||||
(unsigned long)xfer->rx_buf % 4 == 0);
|
(unsigned long)xfer->rx_buf % 4 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mtk_spi_set_hw_cs_timing(struct spi_device *spi,
|
||||||
|
struct spi_delay *setup,
|
||||||
|
struct spi_delay *hold,
|
||||||
|
struct spi_delay *inactive)
|
||||||
|
{
|
||||||
|
struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
|
||||||
|
u16 setup_dly, hold_dly, inactive_dly;
|
||||||
|
u32 reg_val;
|
||||||
|
|
||||||
|
if ((setup && setup->unit != SPI_DELAY_UNIT_SCK) ||
|
||||||
|
(hold && hold->unit != SPI_DELAY_UNIT_SCK) ||
|
||||||
|
(inactive && inactive->unit != SPI_DELAY_UNIT_SCK)) {
|
||||||
|
dev_err(&spi->dev,
|
||||||
|
"Invalid delay unit, should be SPI_DELAY_UNIT_SCK\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_dly = setup ? setup->value : 1;
|
||||||
|
hold_dly = hold ? hold->value : 1;
|
||||||
|
inactive_dly = inactive ? inactive->value : 1;
|
||||||
|
|
||||||
|
reg_val = readl(mdata->base + SPI_CFG0_REG);
|
||||||
|
if (mdata->dev_comp->enhance_timing) {
|
||||||
|
reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
|
||||||
|
reg_val |= (((hold_dly - 1) & 0xffff)
|
||||||
|
<< SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
|
||||||
|
reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
|
||||||
|
reg_val |= (((setup_dly - 1) & 0xffff)
|
||||||
|
<< SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
|
||||||
|
} else {
|
||||||
|
reg_val &= ~(0xff << SPI_CFG0_CS_HOLD_OFFSET);
|
||||||
|
reg_val |= (((hold_dly - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
|
||||||
|
reg_val &= ~(0xff << SPI_CFG0_CS_SETUP_OFFSET);
|
||||||
|
reg_val |= (((setup_dly - 1) & 0xff)
|
||||||
|
<< SPI_CFG0_CS_SETUP_OFFSET);
|
||||||
|
}
|
||||||
|
writel(reg_val, mdata->base + SPI_CFG0_REG);
|
||||||
|
|
||||||
|
reg_val = readl(mdata->base + SPI_CFG1_REG);
|
||||||
|
reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
|
||||||
|
reg_val |= (((inactive_dly - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
|
||||||
|
writel(reg_val, mdata->base + SPI_CFG1_REG);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int mtk_spi_setup(struct spi_device *spi)
|
static int mtk_spi_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
|
struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
|
||||||
|
@ -644,6 +683,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
|
||||||
master->transfer_one = mtk_spi_transfer_one;
|
master->transfer_one = mtk_spi_transfer_one;
|
||||||
master->can_dma = mtk_spi_can_dma;
|
master->can_dma = mtk_spi_can_dma;
|
||||||
master->setup = mtk_spi_setup;
|
master->setup = mtk_spi_setup;
|
||||||
|
master->set_cs_timing = mtk_spi_set_hw_cs_timing;
|
||||||
|
|
||||||
of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node);
|
of_id = of_match_node(mtk_spi_of_match, pdev->dev.of_node);
|
||||||
if (!of_id) {
|
if (!of_id) {
|
||||||
|
|
Loading…
Reference in New Issue