linux/drivers/spi/spi-meson-spicc.c

/*
 * Driver for Amlogic Meson SPI communication controller (SPICC)
 *
 * Copyright (C) BayLibre, SAS
 * Author: Neil Armstrong <[email protected]>
 *
 * SPDX-License-Identifier: GPL-2.0+
 */

#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/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/reset.h>
#include <linux/pinctrl/consumer.h>

/*
 * The Meson SPICC controller could support DMA based transfers, but is not
 * implemented by the vendor code, and while having the registers documentation
 * it has never worked on the GXL Hardware.
 * The PIO mode is the only mode implemented, and due to badly designed HW :
 * - all transfers are cutted in 16 words burst because the FIFO hangs on
 *   TX underflow, and there is no TX "Half-Empty" interrupt, so we go by
 *   FIFO max size chunk only
 * - CS management is dumb, and goes UP between every burst, so is really a
 *   "Data Valid" signal than a Chip Select, GPIO link should be used instead
 *   to have a CS go down over the full transfer
 */

#define SPICC_MAX_BURST

/* Register Map */
#define SPICC_RXDATA

#define SPICC_TXDATA

#define SPICC_CONREG
#define SPICC_ENABLE
#define SPICC_MODE_MASTER
#define SPICC_XCH
#define SPICC_SMC
#define SPICC_POL
#define SPICC_PHA
#define SPICC_SSCTL
#define SPICC_SSPOL
#define SPICC_DRCTL_MASK
#define SPICC_DRCTL_IGNORE
#define SPICC_DRCTL_FALLING
#define SPICC_DRCTL_LOWLEVEL
#define SPICC_CS_MASK
#define SPICC_DATARATE_MASK
#define SPICC_DATARATE_DIV4
#define SPICC_DATARATE_DIV8
#define SPICC_DATARATE_DIV16
#define SPICC_DATARATE_DIV32
#define SPICC_BITLENGTH_MASK
#define SPICC_BURSTLENGTH_MASK

#define SPICC_INTREG
#define SPICC_TE_EN
#define SPICC_TH_EN
#define SPICC_TF_EN
#define SPICC_RR_EN
#define SPICC_RH_EN
#define SPICC_RF_EN
#define SPICC_RO_EN
#define SPICC_TC_EN

#define SPICC_DMAREG
#define SPICC_DMA_ENABLE
#define SPICC_TXFIFO_THRESHOLD_MASK
#define SPICC_RXFIFO_THRESHOLD_MASK
#define SPICC_READ_BURST_MASK
#define SPICC_WRITE_BURST_MASK
#define SPICC_DMA_URGENT
#define SPICC_DMA_THREADID_MASK
#define SPICC_DMA_BURSTNUM_MASK

#define SPICC_STATREG
#define SPICC_TE
#define SPICC_TH
#define SPICC_TF
#define SPICC_RR
#define SPICC_RH
#define SPICC_RF
#define SPICC_RO
#define SPICC_TC

#define SPICC_PERIODREG
#define SPICC_PERIOD

#define SPICC_TESTREG
#define SPICC_TXCNT_MASK
#define SPICC_RXCNT_MASK
#define SPICC_SMSTATUS_MASK
#define SPICC_LBC_RO
#define SPICC_LBC_W1
#define SPICC_SWAP_RO
#define SPICC_SWAP_W1
#define SPICC_DLYCTL_RO_MASK
#define SPICC_MO_DELAY_MASK
#define SPICC_MO_NO_DELAY
#define SPICC_MO_DELAY_1_CYCLE
#define SPICC_MO_DELAY_2_CYCLE
#define SPICC_MO_DELAY_3_CYCLE
#define SPICC_MI_DELAY_MASK
#define SPICC_MI_NO_DELAY
#define SPICC_MI_DELAY_1_CYCLE
#define SPICC_MI_DELAY_2_CYCLE
#define SPICC_MI_DELAY_3_CYCLE
#define SPICC_MI_CAP_DELAY_MASK
#define SPICC_CAP_AHEAD_2_CYCLE
#define SPICC_CAP_AHEAD_1_CYCLE
#define SPICC_CAP_NO_DELAY
#define SPICC_CAP_DELAY_1_CYCLE
#define SPICC_FIFORST_RO_MASK
#define SPICC_FIFORST_W1_MASK

#define SPICC_DRADDR

#define SPICC_DWADDR

#define SPICC_ENH_CTL0
#define SPICC_ENH_CLK_CS_DELAY_MASK
#define SPICC_ENH_DATARATE_MASK
#define SPICC_ENH_DATARATE_EN
#define SPICC_ENH_MOSI_OEN
#define SPICC_ENH_CLK_OEN
#define SPICC_ENH_CS_OEN
#define SPICC_ENH_CLK_CS_DELAY_EN
#define SPICC_ENH_MAIN_CLK_AO

#define writel_bits_relaxed(mask, val, addr)

struct meson_spicc_data {};

struct meson_spicc_device {};

#define pow2_clk_to_spicc(_div)

static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
{}

static inline bool meson_spicc_txfull(struct meson_spicc_device *spicc)
{}

static inline bool meson_spicc_rxready(struct meson_spicc_device *spicc)
{}

static inline u32 meson_spicc_pull_data(struct meson_spicc_device *spicc)
{}

static inline void meson_spicc_push_data(struct meson_spicc_device *spicc,
					 u32 data)
{}

static inline void meson_spicc_rx(struct meson_spicc_device *spicc)
{}

static inline void meson_spicc_tx(struct meson_spicc_device *spicc)
{}

static inline void meson_spicc_setup_burst(struct meson_spicc_device *spicc)
{}

static irqreturn_t meson_spicc_irq(int irq, void *data)
{}

static void meson_spicc_auto_io_delay(struct meson_spicc_device *spicc)
{}

static void meson_spicc_setup_xfer(struct meson_spicc_device *spicc,
				   struct spi_transfer *xfer)
{}

static void meson_spicc_reset_fifo(struct meson_spicc_device *spicc)
{}

static int meson_spicc_transfer_one(struct spi_controller *host,
				    struct spi_device *spi,
				    struct spi_transfer *xfer)
{}

static int meson_spicc_prepare_message(struct spi_controller *host,
				       struct spi_message *message)
{}

static int meson_spicc_unprepare_transfer(struct spi_controller *host)
{}

static int meson_spicc_setup(struct spi_device *spi)
{}

static void meson_spicc_cleanup(struct spi_device *spi)
{}

/*
 * The Clock Mux
 *            x-----------------x   x------------x    x------\
 *        |---| pow2 fixed div  |---| pow2 div   |----|      |
 *        |   x-----------------x   x------------x    |      |
 * src ---|                                           | mux  |-- out
 *        |   x-----------------x   x------------x    |      |
 *        |---| enh fixed div   |---| enh div    |0---|      |
 *            x-----------------x   x------------x    x------/
 *
 * Clk path for GX series:
 *    src -> pow2 fixed div -> pow2 div -> out
 *
 * Clk path for AXG series:
 *    src -> pow2 fixed div -> pow2 div -> mux -> out
 *    src -> enh fixed div -> enh div -> mux -> out
 *
 * Clk path for G12A series:
 *    pclk -> pow2 fixed div -> pow2 div -> mux -> out
 *    pclk -> enh fixed div -> enh div -> mux -> out
 *
 * The pow2 divider is tied to the controller HW state, and the
 * divider is only valid when the controller is initialized.
 *
 * A set of clock ops is added to make sure we don't read/set this
 * clock rate while the controller is in an unknown state.
 */

static unsigned long meson_spicc_pow2_recalc_rate(struct clk_hw *hw,
						  unsigned long parent_rate)
{}

static int meson_spicc_pow2_determine_rate(struct clk_hw *hw,
					   struct clk_rate_request *req)
{}

static int meson_spicc_pow2_set_rate(struct clk_hw *hw, unsigned long rate,
				     unsigned long parent_rate)
{}

static const struct clk_ops meson_spicc_pow2_clk_ops =;

static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc)
{}

static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc)
{}

static int meson_spicc_probe(struct platform_device *pdev)
{}

static void meson_spicc_remove(struct platform_device *pdev)
{}

static const struct meson_spicc_data meson_spicc_gx_data =;

static const struct meson_spicc_data meson_spicc_axg_data =;

static const struct meson_spicc_data meson_spicc_g12a_data =;

static const struct of_device_id meson_spicc_of_match[] =;
MODULE_DEVICE_TABLE(of, meson_spicc_of_match);

static struct platform_driver meson_spicc_driver =;

module_platform_driver();

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();