// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * SDIO clock driver for RP1
 *
 * Copyright (C) 2023 Raspberry Pi Ltd.
 */

#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>

// Register    : MODE
#define MODE        0x00000000
#define MODE_BITS   0x70030000
#define MODE_RESET  0x00000000
// Field       : MODE_STEPS_PER_CYCLE
#define MODE_STEPS_PER_CYCLE_RESET          0x0
#define MODE_STEPS_PER_CYCLE_BITS           0x70000000
#define MODE_STEPS_PER_CYCLE_MSB            30
#define MODE_STEPS_PER_CYCLE_LSB            28
#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_20 0x0
#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_10 0x1
#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_16 0x2
#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_8  0x3
#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_12 0x4
#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_6  0x5
#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_5  0x6
#define MODE_STEPS_PER_CYCLE_VALUE_STEPS_4  0x7
// Field       : MODE_SRC_SEL
#define MODE_SRC_SEL_RESET                   0x0
#define MODE_SRC_SEL_BITS                    0x00030000
#define MODE_SRC_SEL_MSB                     17
#define MODE_SRC_SEL_LSB                     16
#define MODE_SRC_SEL_VALUE_STOP              0x0
#define MODE_SRC_SEL_VALUE_CLK_ALT_SRC       0x1
#define MODE_SRC_SEL_VALUE_PLL_SYS_VCO       0x2
#define MODE_SRC_SEL_VALUE_PLL_SYS_VCO_AGAIN 0x3
// Register    : FROMIP
#define FROMIP        0x00000004
#define FROMIP_BITS   0x0f9713ff
#define FROMIP_RESET  0x00000000
// Field       : FROMIP_TUNING_CCLK_SEL
#define FROMIP_TUNING_CCLK_SEL_RESET  0x0
#define FROMIP_TUNING_CCLK_SEL_BITS   0x0f000000
#define FROMIP_TUNING_CCLK_SEL_MSB    27
#define FROMIP_TUNING_CCLK_SEL_LSB    24
// Field       : FROMIP_TUNING_CCLK_UPDATE
#define FROMIP_TUNING_CCLK_UPDATE_RESET  0x0
#define FROMIP_TUNING_CCLK_UPDATE_BITS   0x00800000
#define FROMIP_TUNING_CCLK_UPDATE_MSB    23
#define FROMIP_TUNING_CCLK_UPDATE_LSB    23
// Field       : FROMIP_SAMPLE_CCLK_SEL
#define FROMIP_SAMPLE_CCLK_SEL_RESET  0x0
#define FROMIP_SAMPLE_CCLK_SEL_BITS   0x00100000
#define FROMIP_SAMPLE_CCLK_SEL_MSB    20
#define FROMIP_SAMPLE_CCLK_SEL_LSB    20
// Field       : FROMIP_CLK2CARD_ON
#define FROMIP_CLK2CARD_ON_RESET  0x0
#define FROMIP_CLK2CARD_ON_BITS   0x00040000
#define FROMIP_CLK2CARD_ON_MSB    18
#define FROMIP_CLK2CARD_ON_LSB    18
// Field       : FROMIP_CARD_CLK_STABLE
#define FROMIP_CARD_CLK_STABLE_RESET  0x0
#define FROMIP_CARD_CLK_STABLE_BITS   0x00020000
#define FROMIP_CARD_CLK_STABLE_MSB    17
#define FROMIP_CARD_CLK_STABLE_LSB    17
// Field       : FROMIP_CARD_CLK_EN
#define FROMIP_CARD_CLK_EN_RESET  0x0
#define FROMIP_CARD_CLK_EN_BITS   0x00010000
#define FROMIP_CARD_CLK_EN_MSB    16
#define FROMIP_CARD_CLK_EN_LSB    16
// Field       : FROMIP_CLK_GEN_SEL
#define FROMIP_CLK_GEN_SEL_RESET  0x0
#define FROMIP_CLK_GEN_SEL_BITS   0x00001000
#define FROMIP_CLK_GEN_SEL_MSB    12
#define FROMIP_CLK_GEN_SEL_LSB    12
// Field       : FROMIP_FREQ_SEL
#define FROMIP_FREQ_SEL_RESET  0x000
#define FROMIP_FREQ_SEL_BITS   0x000003ff
#define FROMIP_FREQ_SEL_MSB    9
#define FROMIP_FREQ_SEL_LSB    0
// Register    : LOCAL
#define LOCAL        0x00000008
#define LOCAL_BITS   0x1f9713ff
#define LOCAL_RESET  0x00000000
// Field       : LOCAL_TUNING_CCLK_SEL
#define LOCAL_TUNING_CCLK_SEL_RESET  0x00
#define LOCAL_TUNING_CCLK_SEL_BITS   0x1f000000
#define LOCAL_TUNING_CCLK_SEL_MSB    28
#define LOCAL_TUNING_CCLK_SEL_LSB    24
// Field       : LOCAL_TUNING_CCLK_UPDATE
#define LOCAL_TUNING_CCLK_UPDATE_RESET  0x0
#define LOCAL_TUNING_CCLK_UPDATE_BITS   0x00800000
#define LOCAL_TUNING_CCLK_UPDATE_MSB    23
#define LOCAL_TUNING_CCLK_UPDATE_LSB    23
// Field       : LOCAL_SAMPLE_CCLK_SEL
#define LOCAL_SAMPLE_CCLK_SEL_RESET  0x0
#define LOCAL_SAMPLE_CCLK_SEL_BITS   0x00100000
#define LOCAL_SAMPLE_CCLK_SEL_MSB    20
#define LOCAL_SAMPLE_CCLK_SEL_LSB    20
// Field       : LOCAL_CLK2CARD_ON
#define LOCAL_CLK2CARD_ON_RESET  0x0
#define LOCAL_CLK2CARD_ON_BITS   0x00040000
#define LOCAL_CLK2CARD_ON_MSB    18
#define LOCAL_CLK2CARD_ON_LSB    18
// Field       : LOCAL_CARD_CLK_STABLE
#define LOCAL_CARD_CLK_STABLE_RESET  0x0
#define LOCAL_CARD_CLK_STABLE_BITS   0x00020000
#define LOCAL_CARD_CLK_STABLE_MSB    17
#define LOCAL_CARD_CLK_STABLE_LSB    17
// Field       : LOCAL_CARD_CLK_EN
#define LOCAL_CARD_CLK_EN_RESET  0x0
#define LOCAL_CARD_CLK_EN_BITS   0x00010000
#define LOCAL_CARD_CLK_EN_MSB    16
#define LOCAL_CARD_CLK_EN_LSB    16
// Field       : LOCAL_CLK_GEN_SEL
#define LOCAL_CLK_GEN_SEL_RESET               0x0
#define LOCAL_CLK_GEN_SEL_BITS                0x00001000
#define LOCAL_CLK_GEN_SEL_MSB                 12
#define LOCAL_CLK_GEN_SEL_LSB                 12
#define LOCAL_CLK_GEN_SEL_VALUE_PROGCLOCKMODE 0x0
#define LOCAL_CLK_GEN_SEL_VALUE_DIVCLOCKMODE  0x1
// Field       : LOCAL_FREQ_SEL
#define LOCAL_FREQ_SEL_RESET  0x000
#define LOCAL_FREQ_SEL_BITS   0x000003ff
#define LOCAL_FREQ_SEL_MSB    9
#define LOCAL_FREQ_SEL_LSB    0
// Register    : USE_LOCAL
#define USE_LOCAL        0x0000000c
#define USE_LOCAL_BITS   0x01951001
#define USE_LOCAL_RESET  0x00000000
// Field       : USE_LOCAL_TUNING_CCLK_SEL
#define USE_LOCAL_TUNING_CCLK_SEL_RESET  0x0
#define USE_LOCAL_TUNING_CCLK_SEL_BITS   0x01000000
#define USE_LOCAL_TUNING_CCLK_SEL_MSB    24
#define USE_LOCAL_TUNING_CCLK_SEL_LSB    24
// Field       : USE_LOCAL_TUNING_CCLK_UPDATE
#define USE_LOCAL_TUNING_CCLK_UPDATE_RESET  0x0
#define USE_LOCAL_TUNING_CCLK_UPDATE_BITS   0x00800000
#define USE_LOCAL_TUNING_CCLK_UPDATE_MSB    23
#define USE_LOCAL_TUNING_CCLK_UPDATE_LSB    23
// Field       : USE_LOCAL_SAMPLE_CCLK_SEL
#define USE_LOCAL_SAMPLE_CCLK_SEL_RESET  0x0
#define USE_LOCAL_SAMPLE_CCLK_SEL_BITS   0x00100000
#define USE_LOCAL_SAMPLE_CCLK_SEL_MSB    20
#define USE_LOCAL_SAMPLE_CCLK_SEL_LSB    20
// Field       : USE_LOCAL_CLK2CARD_ON
#define USE_LOCAL_CLK2CARD_ON_RESET  0x0
#define USE_LOCAL_CLK2CARD_ON_BITS   0x00040000
#define USE_LOCAL_CLK2CARD_ON_MSB    18
#define USE_LOCAL_CLK2CARD_ON_LSB    18
// Field       : USE_LOCAL_CARD_CLK_EN
#define USE_LOCAL_CARD_CLK_EN_RESET  0x0
#define USE_LOCAL_CARD_CLK_EN_BITS   0x00010000
#define USE_LOCAL_CARD_CLK_EN_MSB    16
#define USE_LOCAL_CARD_CLK_EN_LSB    16
// Field       : USE_LOCAL_CLK_GEN_SEL
#define USE_LOCAL_CLK_GEN_SEL_RESET  0x0
#define USE_LOCAL_CLK_GEN_SEL_BITS   0x00001000
#define USE_LOCAL_CLK_GEN_SEL_MSB    12
#define USE_LOCAL_CLK_GEN_SEL_LSB    12
// Field       : USE_LOCAL_FREQ_SEL
#define USE_LOCAL_FREQ_SEL_RESET  0x0
#define USE_LOCAL_FREQ_SEL_BITS   0x00000001
#define USE_LOCAL_FREQ_SEL_MSB    0
#define USE_LOCAL_FREQ_SEL_LSB    0
// Register    : SD_DELAY
#define SD_DELAY        0x00000010
#define SD_DELAY_BITS   0x0000001f
#define SD_DELAY_RESET  0x00000000
// Field       : SD_DELAY_STEPS
#define SD_DELAY_STEPS_RESET  0x00
#define SD_DELAY_STEPS_BITS   0x0000001f
#define SD_DELAY_STEPS_MSB    4
#define SD_DELAY_STEPS_LSB    0
// Register    : RX_DELAY
#define RX_DELAY        0x00000014
#define RX_DELAY_BITS   0x19f3331f
#define RX_DELAY_RESET  0x00000000
// Field       : RX_DELAY_BYPASS
#define RX_DELAY_BYPASS_RESET  0x0
#define RX_DELAY_BYPASS_BITS   0x10000000
#define RX_DELAY_BYPASS_MSB    28
#define RX_DELAY_BYPASS_LSB    28
// Field       : RX_DELAY_FAIL_ACTUAL
#define RX_DELAY_FAIL_ACTUAL_RESET  0x0
#define RX_DELAY_FAIL_ACTUAL_BITS   0x08000000
#define RX_DELAY_FAIL_ACTUAL_MSB    27
#define RX_DELAY_FAIL_ACTUAL_LSB    27
// Field       : RX_DELAY_ACTUAL
#define RX_DELAY_ACTUAL_RESET  0x00
#define RX_DELAY_ACTUAL_BITS   0x01f00000
#define RX_DELAY_ACTUAL_MSB    24
#define RX_DELAY_ACTUAL_LSB    20
// Field       : RX_DELAY_OFFSET
#define RX_DELAY_OFFSET_RESET  0x0
#define RX_DELAY_OFFSET_BITS   0x00030000
#define RX_DELAY_OFFSET_MSB    17
#define RX_DELAY_OFFSET_LSB    16
// Field       : RX_DELAY_OVERFLOW
#define RX_DELAY_OVERFLOW_RESET       0x0
#define RX_DELAY_OVERFLOW_BITS        0x00003000
#define RX_DELAY_OVERFLOW_MSB         13
#define RX_DELAY_OVERFLOW_LSB         12
#define RX_DELAY_OVERFLOW_VALUE_ALLOW 0x0
#define RX_DELAY_OVERFLOW_VALUE_CLAMP 0x1
#define RX_DELAY_OVERFLOW_VALUE_FAIL  0x2
// Field       : RX_DELAY_MAP
#define RX_DELAY_MAP_RESET         0x0
#define RX_DELAY_MAP_BITS          0x00000300
#define RX_DELAY_MAP_MSB           9
#define RX_DELAY_MAP_LSB           8
#define RX_DELAY_MAP_VALUE_DIRECT  0x0
#define RX_DELAY_MAP_VALUE         0x1
#define RX_DELAY_MAP_VALUE_STRETCH 0x2
// Field       : RX_DELAY_FIXED
#define RX_DELAY_FIXED_RESET  0x00
#define RX_DELAY_FIXED_BITS   0x0000001f
#define RX_DELAY_FIXED_MSB    4
#define RX_DELAY_FIXED_LSB    0
// Register    : NDIV
#define NDIV        0x00000018
#define NDIV_BITS   0x1fff0000
#define NDIV_RESET  0x00110000
// Field       : NDIV_DIVB
#define NDIV_DIVB_RESET  0x001
#define NDIV_DIVB_BITS   0x1ff00000
#define NDIV_DIVB_MSB    28
#define NDIV_DIVB_LSB    20
// Field       : NDIV_DIVA
#define NDIV_DIVA_RESET  0x1
#define NDIV_DIVA_BITS   0x000f0000
#define NDIV_DIVA_MSB    19
#define NDIV_DIVA_LSB    16
// Register    : CS
#define CS        0x0000001c
#define CS_BITS   0x00111101
#define CS_RESET  0x00000001
// Field       : CS_RX_DEL_UPDATED
#define CS_RX_DEL_UPDATED_RESET  0x0
#define CS_RX_DEL_UPDATED_BITS   0x00100000
#define CS_RX_DEL_UPDATED_MSB    20
#define CS_RX_DEL_UPDATED_LSB    20
// Field       : CS_RX_CLK_RUNNING
#define CS_RX_CLK_RUNNING_RESET  0x0
#define CS_RX_CLK_RUNNING_BITS   0x00010000
#define CS_RX_CLK_RUNNING_MSB    16
#define CS_RX_CLK_RUNNING_LSB    16
// Field       : CS_SD_CLK_RUNNING
#define CS_SD_CLK_RUNNING_RESET  0x0
#define CS_SD_CLK_RUNNING_BITS   0x00001000
#define CS_SD_CLK_RUNNING_MSB    12
#define CS_SD_CLK_RUNNING_LSB    12
// Field       : CS_TX_CLK_RUNNING
#define CS_TX_CLK_RUNNING_RESET  0x0
#define CS_TX_CLK_RUNNING_BITS   0x00000100
#define CS_TX_CLK_RUNNING_MSB    8
#define CS_TX_CLK_RUNNING_LSB    8
// Field       : CS_RESET
#define CS_RESET_RESET  0x1
#define CS_RESET_BITS   0x00000001
#define CS_RESET_MSB    0
#define CS_RESET_LSB    0

#define FPGA_SRC_RATE 400000000

/* Base number of steps to delay in relation to tx clk.
 * The relationship of the 3 clocks are as follows:
 * tx_clk: This clock is provided to the controller. Data is sent out
 * to the pads using this clock.
 * sd_clk: This clock is sent out to the card.
 * rx_clk: This clock is used to sample the data coming back from the card.
 * This may need to be several steps ahead of the tx_clk. The default rx delay
 * is used as a base delay, and can be further adjusted by the sd host
 * controller during the tuning process if using a DDR50 or faster SD card
 */
/*
 * PRJY-1813 - the default SD clock delay needs to be set to ~60% of the total
 * number of steps to meet tISU (>6ns) and tIH (>2ns) in high-speed mode.
 * On FPGA this means delay SDCLK by 5, and sample RX with a delay of 6.
 */
#define DEFAULT_RX_DELAY 6
#define DEFAULT_SD_DELAY 5

struct rp1_sdio_clkgen {
	struct device *dev;

	/* Source clock. Either PLL VCO or fixed freq on FPGA */
	struct clk *src_clk;
	/* Desired base frequency. Max freq card can go */
	struct clk *base_clk;

	struct clk_hw hw;
	void __iomem *regs;

	/* Starting value of local register before changing freq */
	u32 local_base;
};

static inline void clkgen_write(struct rp1_sdio_clkgen *clkgen, u32 reg, u32 val)
{
	dev_dbg(clkgen->dev, "%s: write reg 0x%x: 0x%x\n", __func__, reg, val);
	writel(val, clkgen->regs + reg);
}

static inline u32 clkgen_read(struct rp1_sdio_clkgen *clkgen, u32 reg)
{
	u32 val = readl(clkgen->regs + reg);

	dev_dbg(clkgen->dev, "%s: read reg 0x%x: 0x%x\n", __func__, reg, val);
	return val;
}

static int get_steps(unsigned int steps)
{
	int ret = -1;

	if (steps == 4)
		ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_4;
	else if (steps == 5)
		ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_5;
	else if (steps == 6)
		ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_6;
	else if (steps == 8)
		ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_8;
	else if (steps == 10)
		ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_10;
	else if (steps == 12)
		ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_12;
	else if (steps == 16)
		ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_16;
	else if (steps == 20)
		ret = MODE_STEPS_PER_CYCLE_VALUE_STEPS_20;
	return ret;
}

static int rp1_sdio_clk_init(struct rp1_sdio_clkgen *clkgen)
{
	unsigned long src_rate = clk_get_rate(clkgen->src_clk);
	unsigned long base_rate = clk_get_rate(clkgen->base_clk);
	unsigned int steps = src_rate / base_rate;
	u32 reg = 0;
	int steps_value = 0;

	dev_dbg(clkgen->dev, "init: src_rate %lu, base_rate %lu, steps %d\n",
		src_rate, base_rate, steps);

	/* Assert reset while we set up clkgen */
	clkgen_write(clkgen, CS, CS_RESET_BITS);

	/* Pick clock source */
	if (src_rate == FPGA_SRC_RATE) {
		/* Using ALT SRC */
		reg |= MODE_SRC_SEL_VALUE_CLK_ALT_SRC << MODE_SRC_SEL_LSB;
	} else {
		/* Assume we are using PLL SYS VCO */
		reg |= MODE_SRC_SEL_VALUE_PLL_SYS_VCO << MODE_SRC_SEL_LSB;
	}

	/* How many delay steps are available in one cycle for this source */
	steps_value = get_steps(steps);
	if (steps_value < 0) {
		dev_err(clkgen->dev, "Invalid step value: %d\n", steps);
		return -EINVAL;
	}
	reg |= steps_value << MODE_STEPS_PER_CYCLE_LSB;

	/* Mode register is done now*/
	clkgen_write(clkgen, MODE, reg);

	/* Now set delay mode */
	/* Clamp value if out of range rx delay is used */
	reg = RX_DELAY_OVERFLOW_VALUE_CLAMP << RX_DELAY_OVERFLOW_LSB;
	/* SD tuning bus goes from 0x0 to 0xf but we don't necessarily have that
	 * many steps available depending on the source so map 0x0 -> 0xf to one
	 * cycle of rx delay
	 */
	reg |= RX_DELAY_MAP_VALUE_STRETCH << RX_DELAY_MAP_LSB;

	/* Default RX delay */
	dev_dbg(clkgen->dev, "default rx delay %d\n", DEFAULT_RX_DELAY);
	reg |= (DEFAULT_RX_DELAY & RX_DELAY_FIXED_BITS) << RX_DELAY_FIXED_LSB;
	clkgen_write(clkgen, RX_DELAY, reg);

	/* Default SD delay */
	dev_dbg(clkgen->dev, "default sd delay %d\n", DEFAULT_SD_DELAY);
	reg = (DEFAULT_SD_DELAY & SD_DELAY_STEPS_BITS) << SD_DELAY_STEPS_LSB;
	clkgen_write(clkgen, SD_DELAY, reg);

	/* We select freq, we turn on tx clock, we turn on sd clk,
	 * we pick clock generator mode
	 */
	reg = USE_LOCAL_FREQ_SEL_BITS | USE_LOCAL_CARD_CLK_EN_BITS |
	      USE_LOCAL_CLK2CARD_ON_BITS | USE_LOCAL_CLK_GEN_SEL_BITS;
	clkgen_write(clkgen, USE_LOCAL, reg);

	/* Deassert reset. Reset bit is only writable bit of CS
	 * reg so fine to write a 0.
	 */
	clkgen_write(clkgen, CS, 0);

	return 0;
}

#define RUNNING	\
	(CS_TX_CLK_RUNNING_BITS | CS_RX_CLK_RUNNING_BITS | \
	 CS_SD_CLK_RUNNING_BITS)
static int rp1_sdio_clk_is_prepared(struct clk_hw *hw)
{
	struct rp1_sdio_clkgen *clkgen =
		container_of(hw, struct rp1_sdio_clkgen, hw);
	u32 status;

	dev_dbg(clkgen->dev, "is_prepared\n");
	status = clkgen_read(clkgen, CS);
	return ((status & RUNNING) == RUNNING);
}

/* Can define an additional divider if an sd card isn't working at full speed */
/* #define SLOWDOWN 3 */

static unsigned long rp1_sdio_clk_get_rate(struct clk_hw *hw,
					   unsigned long parent_rate)
{
	/* Get the current rate */
	struct rp1_sdio_clkgen *clkgen =
		container_of(hw, struct rp1_sdio_clkgen, hw);
	unsigned long actual_rate = 0;
	u32 ndiv_diva;
	u32 ndiv_divb;
	u32 tmp;
	u32 div;

	tmp = clkgen_read(clkgen, LOCAL);
	if ((tmp & LOCAL_CLK2CARD_ON_BITS) == 0) {
		dev_dbg(clkgen->dev, "get_rate 0\n");
		return 0;
	}

	tmp = clkgen_read(clkgen, NDIV);
	ndiv_diva = (tmp & NDIV_DIVA_BITS) >> NDIV_DIVA_LSB;
	ndiv_divb = (tmp & NDIV_DIVB_BITS) >> NDIV_DIVB_LSB;
	div = ndiv_diva * ndiv_divb;
	actual_rate = (clk_get_rate(clkgen->base_clk) / div);

#ifdef SLOWDOWN
	actual_rate *= SLOWDOWN;
#endif

	dev_dbg(clkgen->dev, "get_rate. ndiv_diva %d, ndiv_divb %d = %lu\n",
		ndiv_diva, ndiv_divb, actual_rate);

	return actual_rate;
}

static int rp1_sdio_clk_set_rate(struct clk_hw *hw, unsigned long rate,
				 unsigned long parent_rate)
{
	struct rp1_sdio_clkgen *clkgen =
		container_of(hw, struct rp1_sdio_clkgen, hw);
	u32 div;
	u32 reg;

	dev_dbg(clkgen->dev, "set_rate %lu\n", rate);

	if (rate == 0) {
		/* Keep tx clock running */
		clkgen_write(clkgen, LOCAL, LOCAL_CARD_CLK_EN_BITS);
		return 0;
	}

#ifdef SLOWDOWN
	rate /= SLOWDOWN;
#endif

	div = (clk_get_rate(clkgen->base_clk) / rate) - 1;
	reg = LOCAL_CLK_GEN_SEL_BITS | LOCAL_CARD_CLK_EN_BITS |
	      LOCAL_CLK2CARD_ON_BITS | (div << LOCAL_FREQ_SEL_LSB);
	clkgen_write(clkgen, LOCAL, reg);

	return 0;
}

#define MAX_NDIV (256 * 8)
static int rp1_sdio_clk_determine_rate(struct clk_hw *hw,
				       struct clk_rate_request *req)
{
	unsigned long rate;
	struct rp1_sdio_clkgen *clkgen =
		container_of(hw, struct rp1_sdio_clkgen, hw);
	unsigned long base_rate = clk_get_rate(clkgen->base_clk);
	u32 div;

	/* What is the actual rate I can get if I request xyz */
	if (req->rate) {
		div = min((u32)(base_rate / req->rate), (u32)MAX_NDIV);
		rate = base_rate / div;
		req->rate = rate;
		dev_dbg(clkgen->dev, "determine_rate %lu: %lu / %d = %lu\n",
			req->rate, base_rate, div, rate);
	} else {
		rate = 0;
		dev_dbg(clkgen->dev, "determine_rate %lu: %lu\n", req->rate,
			rate);
	}

	return 0;
}

static const struct clk_ops rp1_sdio_clk_ops = {
	.is_prepared    = rp1_sdio_clk_is_prepared,
	.recalc_rate    = rp1_sdio_clk_get_rate,
	.set_rate       = rp1_sdio_clk_set_rate,
	.determine_rate = rp1_sdio_clk_determine_rate,
};

static int rp1_sdio_clk_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	struct rp1_sdio_clkgen *clkgen;
	void __iomem *regs;
	struct clk_init_data init = {};
	int ret;

	clkgen = devm_kzalloc(&pdev->dev, sizeof(*clkgen), GFP_KERNEL);
	if (!clkgen)
		return -ENOMEM;
	platform_set_drvdata(pdev, clkgen);

	clkgen->dev = &pdev->dev;

	/* Source freq */
	clkgen->src_clk = devm_clk_get(&pdev->dev, "src");
	if (IS_ERR(clkgen->src_clk)) {
		int err = PTR_ERR(clkgen->src_clk);

		dev_err(&pdev->dev, "failed to get src clk: %d\n", err);
		return err;
	}

	/* Desired maximum output freq (i.e. base freq) */
	clkgen->base_clk = devm_clk_get(&pdev->dev, "base");
	if (IS_ERR(clkgen->base_clk)) {
		int err = PTR_ERR(clkgen->base_clk);

		dev_err(&pdev->dev, "failed to get base clk: %d\n", err);
		return err;
	}

	regs = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(regs))
		return PTR_ERR(regs);

	init.name = node->name;
	init.ops = &rp1_sdio_clk_ops;
	init.flags = CLK_GET_RATE_NOCACHE;

	clkgen->hw.init = &init;
	clkgen->regs = regs;

	dev_info(&pdev->dev, "loaded %s\n", init.name);

	ret = devm_clk_hw_register(&pdev->dev, &clkgen->hw);
	if (ret)
		return ret;

	ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &clkgen->hw);
	if (ret)
		return ret;

	ret = rp1_sdio_clk_init(clkgen);
	return ret;
}

static void rp1_sdio_clk_remove(struct platform_device *pdev)
{
}

static const struct of_device_id rp1_sdio_clk_dt_ids[] = {
	{ .compatible = "raspberrypi,rp1-sdio-clk", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rp1_sdio_clk_dt_ids);

static struct platform_driver rp1_sdio_clk_driver = {
	.probe	= rp1_sdio_clk_probe,
	.remove	= rp1_sdio_clk_remove,
	.driver	= {
		.name		= "rp1-sdio-clk",
		.of_match_table	= rp1_sdio_clk_dt_ids,
	},
};
module_platform_driver(rp1_sdio_clk_driver);

MODULE_AUTHOR("Liam Fraser <liam@raspberrypi.com>");
MODULE_DESCRIPTION("RP1 SDIO clock driver");
MODULE_LICENSE("GPL");
