Loading Documentation/devicetree/bindings/spi/cdns,qspi-nor-peripheral-props.yaml +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml +1 −1 Original line number Diff line number Diff line Loading @@ -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# Loading Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +1 −1 Original line number Diff line number Diff line Loading @@ -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: Loading MAINTAINERS +1 −1 Original line number Diff line number Diff line Loading @@ -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* Loading drivers/spi/spi-meson-spicc.c +101 −28 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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]; Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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 Loading
Documentation/devicetree/bindings/spi/cdns,qspi-nor-peripheral-props.yaml +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
Documentation/devicetree/bindings/spi/cdns,qspi-nor.yaml +1 −1 Original line number Diff line number Diff line Loading @@ -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# Loading
Documentation/devicetree/bindings/spi/spi-peripheral-props.yaml +1 −1 Original line number Diff line number Diff line Loading @@ -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: Loading
MAINTAINERS +1 −1 Original line number Diff line number Diff line Loading @@ -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* Loading
drivers/spi/spi-meson-spicc.c +101 −28 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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]; Loading Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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