Unverified Commit 75c971dd authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'spi/for-5.20' into spi-6.0

parents 568035b0 2fd92c7b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ description:
  See spi-peripheral-props.yaml for more info.

maintainers:
  - Pratyush Yadav <p.yadav@ti.com>
  - Vaishnav Achath <vaishnav.a@ti.com>

properties:
  # cdns,qspi-nor.yaml
+1 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cadence Quad SPI controller

maintainers:
  - Pratyush Yadav <p.yadav@ti.com>
  - Vaishnav Achath <vaishnav.a@ti.com>

allOf:
  - $ref: spi-controller.yaml#
+1 −1
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@ description:
  their own separate schema that should be referenced from here.

maintainers:
  - Pratyush Yadav <p.yadav@ti.com>
  - Mark Brown <broonie@kernel.org>

properties:
  reg:
+1 −1
Original line number Diff line number Diff line
@@ -2178,7 +2178,7 @@ M: Jean-Marie Verdun <verdun@hpe.com>
M:	Nick Hawkins <nick.hawkins@hpe.com>
S:	Maintained
F:	Documentation/devicetree/bindings/arm/hpe,gxp.yaml
F:	Documentation/devicetree/bindings/spi/hpe,gxp-spi.yaml
F:	Documentation/devicetree/bindings/spi/hpe,gxp-spifi.yaml
F:	Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
F:	arch/arm/boot/dts/hpe-bmc*
F:	arch/arm/boot/dts/hpe-gxp*
+101 −28
Original line number Diff line number Diff line
@@ -156,6 +156,7 @@ struct meson_spicc_device {
	void __iomem			*base;
	struct clk			*core;
	struct clk			*pclk;
	struct clk_divider		pow2_div;
	struct clk			*clk;
	struct spi_message		*message;
	struct spi_transfer		*xfer;
@@ -168,6 +169,8 @@ struct meson_spicc_device {
	unsigned long			xfer_remain;
};

#define pow2_clk_to_spicc(_div) container_of(_div, struct meson_spicc_device, pow2_div)

static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
{
	u32 conf;
@@ -421,7 +424,7 @@ static int meson_spicc_prepare_message(struct spi_master *master,
{
	struct meson_spicc_device *spicc = spi_master_get_devdata(master);
	struct spi_device *spi = message->spi;
	u32 conf = 0;
	u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK;

	/* Store current message */
	spicc->message = message;
@@ -458,8 +461,6 @@ static int meson_spicc_prepare_message(struct spi_master *master,
	/* Select CS */
	conf |= FIELD_PREP(SPICC_CS_MASK, spi->chip_select);

	/* Default Clock rate core/4 */

	/* Default 8bit word */
	conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, 8 - 1);

@@ -476,12 +477,16 @@ static int meson_spicc_prepare_message(struct spi_master *master,
static int meson_spicc_unprepare_transfer(struct spi_master *master)
{
	struct meson_spicc_device *spicc = spi_master_get_devdata(master);
	u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK;

	/* Disable all IRQs */
	writel(0, spicc->base + SPICC_INTREG);

	device_reset_optional(&spicc->pdev->dev);

	/* Set default configuration, keeping datarate field */
	writel_relaxed(conf, spicc->base + SPICC_CONREG);

	return 0;
}

@@ -518,14 +523,60 @@ static void meson_spicc_cleanup(struct spi_device *spi)
 * 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 int meson_spicc_clk_init(struct meson_spicc_device *spicc)
static unsigned long meson_spicc_pow2_recalc_rate(struct clk_hw *hw,
						  unsigned long parent_rate)
{
	struct clk_divider *divider = to_clk_divider(hw);
	struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);

	if (!spicc->master->cur_msg || !spicc->master->busy)
		return 0;

	return clk_divider_ops.recalc_rate(hw, parent_rate);
}

static int meson_spicc_pow2_determine_rate(struct clk_hw *hw,
					   struct clk_rate_request *req)
{
	struct clk_divider *divider = to_clk_divider(hw);
	struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);

	if (!spicc->master->cur_msg || !spicc->master->busy)
		return -EINVAL;

	return clk_divider_ops.determine_rate(hw, req);
}

static int meson_spicc_pow2_set_rate(struct clk_hw *hw, unsigned long rate,
				     unsigned long parent_rate)
{
	struct clk_divider *divider = to_clk_divider(hw);
	struct meson_spicc_device *spicc = pow2_clk_to_spicc(divider);

	if (!spicc->master->cur_msg || !spicc->master->busy)
		return -EINVAL;

	return clk_divider_ops.set_rate(hw, rate, parent_rate);
}

const struct clk_ops meson_spicc_pow2_clk_ops = {
	.recalc_rate = meson_spicc_pow2_recalc_rate,
	.determine_rate = meson_spicc_pow2_determine_rate,
	.set_rate = meson_spicc_pow2_set_rate,
};

static int meson_spicc_pow2_clk_init(struct meson_spicc_device *spicc)
{
	struct device *dev = &spicc->pdev->dev;
	struct clk_fixed_factor *pow2_fixed_div, *enh_fixed_div;
	struct clk_divider *pow2_div, *enh_div;
	struct clk_mux *mux;
	struct clk_fixed_factor *pow2_fixed_div;
	struct clk_init_data init;
	struct clk *clk;
	struct clk_parent_data parent_data[2];
@@ -560,32 +611,46 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
	if (WARN_ON(IS_ERR(clk)))
		return PTR_ERR(clk);

	pow2_div = devm_kzalloc(dev, sizeof(*pow2_div), GFP_KERNEL);
	if (!pow2_div)
		return -ENOMEM;

	snprintf(name, sizeof(name), "%s#pow2_div", dev_name(dev));
	init.name = name;
	init.ops = &clk_divider_ops;
	init.flags = CLK_SET_RATE_PARENT;
	init.ops = &meson_spicc_pow2_clk_ops;
	/*
	 * Set NOCACHE here to make sure we read the actual HW value
	 * since we reset the HW after each transfer.
	 */
	init.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE;
	parent_data[0].hw = &pow2_fixed_div->hw;
	init.num_parents = 1;

	pow2_div->shift = 16,
	pow2_div->width = 3,
	pow2_div->flags = CLK_DIVIDER_POWER_OF_TWO,
	pow2_div->reg = spicc->base + SPICC_CONREG;
	pow2_div->hw.init = &init;
	spicc->pow2_div.shift = 16,
	spicc->pow2_div.width = 3,
	spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO,
	spicc->pow2_div.reg = spicc->base + SPICC_CONREG;
	spicc->pow2_div.hw.init = &init;

	clk = devm_clk_register(dev, &pow2_div->hw);
	if (WARN_ON(IS_ERR(clk)))
		return PTR_ERR(clk);
	spicc->clk = devm_clk_register(dev, &spicc->pow2_div.hw);
	if (WARN_ON(IS_ERR(spicc->clk)))
		return PTR_ERR(spicc->clk);

	if (!spicc->data->has_enhance_clk_div) {
		spicc->clk = clk;
	return 0;
}

static int meson_spicc_enh_clk_init(struct meson_spicc_device *spicc)
{
	struct device *dev = &spicc->pdev->dev;
	struct clk_fixed_factor *enh_fixed_div;
	struct clk_divider *enh_div;
	struct clk_mux *mux;
	struct clk_init_data init;
	struct clk *clk;
	struct clk_parent_data parent_data[2];
	char name[64];

	memset(&init, 0, sizeof(init));
	memset(&parent_data, 0, sizeof(parent_data));

	init.parent_data = parent_data;

	/* algorithm for enh div: rate = freq / 2 / (N + 1) */

	enh_fixed_div = devm_kzalloc(dev, sizeof(*enh_fixed_div), GFP_KERNEL);
@@ -637,7 +702,7 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
	snprintf(name, sizeof(name), "%s#sel", dev_name(dev));
	init.name = name;
	init.ops = &clk_mux_ops;
	parent_data[0].hw = &pow2_div->hw;
	parent_data[0].hw = &spicc->pow2_div.hw;
	parent_data[1].hw = &enh_div->hw;
	init.num_parents = 2;
	init.flags = CLK_SET_RATE_PARENT;
@@ -754,11 +819,19 @@ static int meson_spicc_probe(struct platform_device *pdev)

	meson_spicc_oen_enable(spicc);

	ret = meson_spicc_clk_init(spicc);
	ret = meson_spicc_pow2_clk_init(spicc);
	if (ret) {
		dev_err(&pdev->dev, "pow2 clock registration failed\n");
		goto out_clk;
	}

	if (spicc->data->has_enhance_clk_div) {
		ret = meson_spicc_enh_clk_init(spicc);
		if (ret) {
			dev_err(&pdev->dev, "clock registration failed\n");
			goto out_clk;
		}
	}

	ret = devm_spi_register_master(&pdev->dev, master);
	if (ret) {
Loading