Commit 75c971dd authored by Mark Brown's avatar Mark Brown

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

parents 568035b0 2fd92c7b
...@@ -10,7 +10,7 @@ description: ...@@ -10,7 +10,7 @@ description:
See spi-peripheral-props.yaml for more info. See spi-peripheral-props.yaml for more info.
maintainers: maintainers:
- Pratyush Yadav <p.yadav@ti.com> - Vaishnav Achath <vaishnav.a@ti.com>
properties: properties:
# cdns,qspi-nor.yaml # cdns,qspi-nor.yaml
......
...@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# ...@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cadence Quad SPI controller title: Cadence Quad SPI controller
maintainers: maintainers:
- Pratyush Yadav <p.yadav@ti.com> - Vaishnav Achath <vaishnav.a@ti.com>
allOf: allOf:
- $ref: spi-controller.yaml# - $ref: spi-controller.yaml#
......
...@@ -16,7 +16,7 @@ description: ...@@ -16,7 +16,7 @@ description:
their own separate schema that should be referenced from here. their own separate schema that should be referenced from here.
maintainers: maintainers:
- Pratyush Yadav <p.yadav@ti.com> - Mark Brown <broonie@kernel.org>
properties: properties:
reg: reg:
......
...@@ -2178,7 +2178,7 @@ M: Jean-Marie Verdun <verdun@hpe.com> ...@@ -2178,7 +2178,7 @@ M: Jean-Marie Verdun <verdun@hpe.com>
M: Nick Hawkins <nick.hawkins@hpe.com> M: Nick Hawkins <nick.hawkins@hpe.com>
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/arm/hpe,gxp.yaml 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: Documentation/devicetree/bindings/timer/hpe,gxp-timer.yaml
F: arch/arm/boot/dts/hpe-bmc* F: arch/arm/boot/dts/hpe-bmc*
F: arch/arm/boot/dts/hpe-gxp* F: arch/arm/boot/dts/hpe-gxp*
......
...@@ -156,6 +156,7 @@ struct meson_spicc_device { ...@@ -156,6 +156,7 @@ struct meson_spicc_device {
void __iomem *base; void __iomem *base;
struct clk *core; struct clk *core;
struct clk *pclk; struct clk *pclk;
struct clk_divider pow2_div;
struct clk *clk; struct clk *clk;
struct spi_message *message; struct spi_message *message;
struct spi_transfer *xfer; struct spi_transfer *xfer;
...@@ -168,6 +169,8 @@ struct meson_spicc_device { ...@@ -168,6 +169,8 @@ struct meson_spicc_device {
unsigned long xfer_remain; 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) static void meson_spicc_oen_enable(struct meson_spicc_device *spicc)
{ {
u32 conf; u32 conf;
...@@ -421,7 +424,7 @@ static int meson_spicc_prepare_message(struct spi_master *master, ...@@ -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 meson_spicc_device *spicc = spi_master_get_devdata(master);
struct spi_device *spi = message->spi; struct spi_device *spi = message->spi;
u32 conf = 0; u32 conf = readl_relaxed(spicc->base + SPICC_CONREG) & SPICC_DATARATE_MASK;
/* Store current message */ /* Store current message */
spicc->message = message; spicc->message = message;
...@@ -458,8 +461,6 @@ static int meson_spicc_prepare_message(struct spi_master *master, ...@@ -458,8 +461,6 @@ static int meson_spicc_prepare_message(struct spi_master *master,
/* Select CS */ /* Select CS */
conf |= FIELD_PREP(SPICC_CS_MASK, spi->chip_select); conf |= FIELD_PREP(SPICC_CS_MASK, spi->chip_select);
/* Default Clock rate core/4 */
/* Default 8bit word */ /* Default 8bit word */
conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, 8 - 1); conf |= FIELD_PREP(SPICC_BITLENGTH_MASK, 8 - 1);
...@@ -476,12 +477,16 @@ static int meson_spicc_prepare_message(struct spi_master *master, ...@@ -476,12 +477,16 @@ static int meson_spicc_prepare_message(struct spi_master *master,
static int meson_spicc_unprepare_transfer(struct spi_master *master) static int meson_spicc_unprepare_transfer(struct spi_master *master)
{ {
struct meson_spicc_device *spicc = spi_master_get_devdata(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 */ /* Disable all IRQs */
writel(0, spicc->base + SPICC_INTREG); writel(0, spicc->base + SPICC_INTREG);
device_reset_optional(&spicc->pdev->dev); device_reset_optional(&spicc->pdev->dev);
/* Set default configuration, keeping datarate field */
writel_relaxed(conf, spicc->base + SPICC_CONREG);
return 0; return 0;
} }
...@@ -518,14 +523,60 @@ static void meson_spicc_cleanup(struct spi_device *spi) ...@@ -518,14 +523,60 @@ static void meson_spicc_cleanup(struct spi_device *spi)
* Clk path for G12A series: * Clk path for G12A series:
* pclk -> pow2 fixed div -> pow2 div -> mux -> out * pclk -> pow2 fixed div -> pow2 div -> mux -> out
* pclk -> enh fixed div -> enh 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 device *dev = &spicc->pdev->dev;
struct clk_fixed_factor *pow2_fixed_div, *enh_fixed_div; struct clk_fixed_factor *pow2_fixed_div;
struct clk_divider *pow2_div, *enh_div;
struct clk_mux *mux;
struct clk_init_data init; struct clk_init_data init;
struct clk *clk; struct clk *clk;
struct clk_parent_data parent_data[2]; struct clk_parent_data parent_data[2];
...@@ -560,31 +611,45 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc) ...@@ -560,31 +611,45 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
if (WARN_ON(IS_ERR(clk))) if (WARN_ON(IS_ERR(clk)))
return PTR_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)); snprintf(name, sizeof(name), "%s#pow2_div", dev_name(dev));
init.name = name; init.name = name;
init.ops = &clk_divider_ops; init.ops = &meson_spicc_pow2_clk_ops;
init.flags = CLK_SET_RATE_PARENT; /*
* 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; parent_data[0].hw = &pow2_fixed_div->hw;
init.num_parents = 1; init.num_parents = 1;
pow2_div->shift = 16, spicc->pow2_div.shift = 16,
pow2_div->width = 3, spicc->pow2_div.width = 3,
pow2_div->flags = CLK_DIVIDER_POWER_OF_TWO, spicc->pow2_div.flags = CLK_DIVIDER_POWER_OF_TWO,
pow2_div->reg = spicc->base + SPICC_CONREG; spicc->pow2_div.reg = spicc->base + SPICC_CONREG;
pow2_div->hw.init = &init; spicc->pow2_div.hw.init = &init;
clk = devm_clk_register(dev, &pow2_div->hw); spicc->clk = devm_clk_register(dev, &spicc->pow2_div.hw);
if (WARN_ON(IS_ERR(clk))) if (WARN_ON(IS_ERR(spicc->clk)))
return PTR_ERR(clk); return PTR_ERR(spicc->clk);
if (!spicc->data->has_enhance_clk_div) { return 0;
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) */ /* algorithm for enh div: rate = freq / 2 / (N + 1) */
...@@ -637,7 +702,7 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc) ...@@ -637,7 +702,7 @@ static int meson_spicc_clk_init(struct meson_spicc_device *spicc)
snprintf(name, sizeof(name), "%s#sel", dev_name(dev)); snprintf(name, sizeof(name), "%s#sel", dev_name(dev));
init.name = name; init.name = name;
init.ops = &clk_mux_ops; 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; parent_data[1].hw = &enh_div->hw;
init.num_parents = 2; init.num_parents = 2;
init.flags = CLK_SET_RATE_PARENT; init.flags = CLK_SET_RATE_PARENT;
...@@ -754,12 +819,20 @@ static int meson_spicc_probe(struct platform_device *pdev) ...@@ -754,12 +819,20 @@ static int meson_spicc_probe(struct platform_device *pdev)
meson_spicc_oen_enable(spicc); meson_spicc_oen_enable(spicc);
ret = meson_spicc_clk_init(spicc); ret = meson_spicc_pow2_clk_init(spicc);
if (ret) { if (ret) {
dev_err(&pdev->dev, "clock registration failed\n"); dev_err(&pdev->dev, "pow2 clock registration failed\n");
goto out_clk; 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); ret = devm_spi_register_master(&pdev->dev, master);
if (ret) { if (ret) {
dev_err(&pdev->dev, "spi master registration failed\n"); dev_err(&pdev->dev, "spi master registration failed\n");
......
...@@ -95,7 +95,7 @@ static ssize_t driver_override_show(struct device *dev, ...@@ -95,7 +95,7 @@ static ssize_t driver_override_show(struct device *dev,
} }
static DEVICE_ATTR_RW(driver_override); static DEVICE_ATTR_RW(driver_override);
static struct spi_statistics *spi_alloc_pcpu_stats(struct device *dev) static struct spi_statistics __percpu *spi_alloc_pcpu_stats(struct device *dev)
{ {
struct spi_statistics __percpu *pcpu_stats; struct spi_statistics __percpu *pcpu_stats;
...@@ -162,7 +162,7 @@ static struct device_attribute dev_attr_spi_device_##field = { \ ...@@ -162,7 +162,7 @@ static struct device_attribute dev_attr_spi_device_##field = { \
} }
#define SPI_STATISTICS_SHOW_NAME(name, file, field) \ #define SPI_STATISTICS_SHOW_NAME(name, file, field) \
static ssize_t spi_statistics_##name##_show(struct spi_statistics *stat, \ static ssize_t spi_statistics_##name##_show(struct spi_statistics __percpu *stat, \
char *buf) \ char *buf) \
{ \ { \
ssize_t len; \ ssize_t len; \
...@@ -309,7 +309,7 @@ static const struct attribute_group *spi_master_groups[] = { ...@@ -309,7 +309,7 @@ static const struct attribute_group *spi_master_groups[] = {
NULL, NULL,
}; };
static void spi_statistics_add_transfer_stats(struct spi_statistics *pcpu_stats, static void spi_statistics_add_transfer_stats(struct spi_statistics __percpu *pcpu_stats,
struct spi_transfer *xfer, struct spi_transfer *xfer,
struct spi_controller *ctlr) struct spi_controller *ctlr)
{ {
...@@ -1275,8 +1275,8 @@ static int spi_transfer_wait(struct spi_controller *ctlr, ...@@ -1275,8 +1275,8 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
struct spi_message *msg, struct spi_message *msg,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
struct spi_statistics *statm = ctlr->pcpu_statistics; struct spi_statistics __percpu *statm = ctlr->pcpu_statistics;
struct spi_statistics *stats = msg->spi->pcpu_statistics; struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics;
u32 speed_hz = xfer->speed_hz; u32 speed_hz = xfer->speed_hz;
unsigned long long ms; unsigned long long ms;
...@@ -1432,8 +1432,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, ...@@ -1432,8 +1432,8 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
struct spi_transfer *xfer; struct spi_transfer *xfer;
bool keep_cs = false; bool keep_cs = false;
int ret = 0; int ret = 0;
struct spi_statistics *statm = ctlr->pcpu_statistics; struct spi_statistics __percpu *statm = ctlr->pcpu_statistics;
struct spi_statistics *stats = msg->spi->pcpu_statistics; struct spi_statistics __percpu *stats = msg->spi->pcpu_statistics;
spi_set_cs(msg->spi, true, false); spi_set_cs(msg->spi, true, false);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment