On 11/07/2017 at 09:40:14 +0200, Ludovic Desroches wrote:
> For HSMC controller, the register layout depends on the device i.e. the
> offset of setup, pulse, cycle, mode and timings registers is not the
> same. An helper is added to provide the correct register layout.
> 
> Fixes: fe9d7cb22ef3 ("mfd: syscon: atmel-smc: Add new helpers to ease
> SMC regs manipulation")
> Suggested-by: Boris Brezillon <boris.brezil...@free-electrons.com>
> Signed-off-by: Ludovic Desroches <ludovic.desroc...@microchip.com>
Acked-by: Alexandre Belloni <alexandre.bell...@free-electrons.com>

> ---
>  drivers/memory/atmel-ebi.c               | 13 +++++--
>  drivers/mfd/atmel-smc.c                  | 67 
> +++++++++++++++++++++++++-------
>  drivers/mtd/nand/atmel/nand-controller.c | 10 +++--
>  include/linux/mfd/syscon/atmel-smc.h     | 32 ++++++++++-----
>  4 files changed, 92 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c
> index 99e644cda4d1..63c9e7a76854 100644
> --- a/drivers/memory/atmel-ebi.c
> +++ b/drivers/memory/atmel-ebi.c
> @@ -51,6 +51,7 @@ struct atmel_ebi {
>       struct  {
>               struct regmap *regmap;
>               struct clk *clk;
> +             const struct atmel_hsmc_reg_layout *layout;
>       } smc;
>  
>       struct device *dev;
> @@ -84,8 +85,8 @@ static void at91sam9_ebi_get_config(struct atmel_ebi_dev 
> *ebid,
>  static void sama5_ebi_get_config(struct atmel_ebi_dev *ebid,
>                                struct atmel_ebi_dev_config *conf)
>  {
> -     atmel_hsmc_cs_conf_get(ebid->ebi->smc.regmap, conf->cs,
> -                            &conf->smcconf);
> +     atmel_hsmc_cs_conf_get(ebid->ebi->smc.regmap, ebid->ebi->smc.layout,
> +                            conf->cs, &conf->smcconf);
>  }
>  
>  static const struct atmel_smc_timing_xlate timings_xlate_table[] = {
> @@ -285,8 +286,8 @@ static void at91sam9_ebi_apply_config(struct 
> atmel_ebi_dev *ebid,
>  static void sama5_ebi_apply_config(struct atmel_ebi_dev *ebid,
>                                  struct atmel_ebi_dev_config *conf)
>  {
> -     atmel_hsmc_cs_conf_apply(ebid->ebi->smc.regmap, conf->cs,
> -                              &conf->smcconf);
> +     atmel_hsmc_cs_conf_apply(ebid->ebi->smc.regmap, ebid->ebi->smc.layout,
> +                              conf->cs, &conf->smcconf);
>  }
>  
>  static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
> @@ -525,6 +526,10 @@ static int atmel_ebi_probe(struct platform_device *pdev)
>       if (IS_ERR(ebi->smc.regmap))
>               return PTR_ERR(ebi->smc.regmap);
>  
> +     ebi->smc.layout = atmel_hsmc_get_reg_layout(smc_np);
> +     if (IS_ERR(ebi->smc.layout))
> +             return PTR_ERR(ebi->smc.layout);
> +
>       ebi->smc.clk = of_clk_get(smc_np, 0);
>       if (IS_ERR(ebi->smc.clk)) {
>               if (PTR_ERR(ebi->smc.clk) != -ENOENT)
> diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c
> index 954cf0f66a31..1ad44e63b511 100644
> --- a/drivers/mfd/atmel-smc.c
> +++ b/drivers/mfd/atmel-smc.c
> @@ -258,19 +258,21 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply);
>   * atmel_hsmc_cs_conf_apply - apply an SMC CS conf
>   * @regmap: the HSMC regmap
>   * @cs: the CS id
> + * @layout: the layout of registers
>   * @conf the SMC CS conf to apply
>   *
>   * Applies an SMC CS configuration.
>   * Only valid on post-sama5 SoCs.
>   */
> -void atmel_hsmc_cs_conf_apply(struct regmap *regmap, int cs,
> -                           const struct atmel_smc_cs_conf *conf)
> +void atmel_hsmc_cs_conf_apply(struct regmap *regmap,
> +                           const struct atmel_hsmc_reg_layout *layout,
> +                           int cs, const struct atmel_smc_cs_conf *conf)
>  {
> -     regmap_write(regmap, ATMEL_HSMC_SETUP(cs), conf->setup);
> -     regmap_write(regmap, ATMEL_HSMC_PULSE(cs), conf->pulse);
> -     regmap_write(regmap, ATMEL_HSMC_CYCLE(cs), conf->cycle);
> -     regmap_write(regmap, ATMEL_HSMC_TIMINGS(cs), conf->timings);
> -     regmap_write(regmap, ATMEL_HSMC_MODE(cs), conf->mode);
> +     regmap_write(regmap, ATMEL_HSMC_SETUP(layout, cs), conf->setup);
> +     regmap_write(regmap, ATMEL_HSMC_PULSE(layout, cs), conf->pulse);
> +     regmap_write(regmap, ATMEL_HSMC_CYCLE(layout, cs), conf->cycle);
> +     regmap_write(regmap, ATMEL_HSMC_TIMINGS(layout, cs), conf->timings);
> +     regmap_write(regmap, ATMEL_HSMC_MODE(layout, cs), conf->mode);
>  }
>  EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply);
>  
> @@ -297,18 +299,55 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get);
>   * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf
>   * @regmap: the HSMC regmap
>   * @cs: the CS id
> + * @layout: the layout of registers
>   * @conf: the SMC CS conf object to store the current conf
>   *
>   * Retrieve the SMC CS configuration.
>   * Only valid on post-sama5 SoCs.
>   */
> -void atmel_hsmc_cs_conf_get(struct regmap *regmap, int cs,
> -                         struct atmel_smc_cs_conf *conf)
> +void atmel_hsmc_cs_conf_get(struct regmap *regmap,
> +                         const struct atmel_hsmc_reg_layout *layout,
> +                         int cs, struct atmel_smc_cs_conf *conf)
>  {
> -     regmap_read(regmap, ATMEL_HSMC_SETUP(cs), &conf->setup);
> -     regmap_read(regmap, ATMEL_HSMC_PULSE(cs), &conf->pulse);
> -     regmap_read(regmap, ATMEL_HSMC_CYCLE(cs), &conf->cycle);
> -     regmap_read(regmap, ATMEL_HSMC_TIMINGS(cs), &conf->timings);
> -     regmap_read(regmap, ATMEL_HSMC_MODE(cs), &conf->mode);
> +     regmap_read(regmap, ATMEL_HSMC_SETUP(layout, cs), &conf->setup);
> +     regmap_read(regmap, ATMEL_HSMC_PULSE(layout, cs), &conf->pulse);
> +     regmap_read(regmap, ATMEL_HSMC_CYCLE(layout, cs), &conf->cycle);
> +     regmap_read(regmap, ATMEL_HSMC_TIMINGS(layout, cs), &conf->timings);
> +     regmap_read(regmap, ATMEL_HSMC_MODE(layout, cs), &conf->mode);
>  }
>  EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get);
> +
> +static const struct atmel_hsmc_reg_layout sama5d3_reg_layout = {
> +     .timing_regs_offset = 0x600,
> +};
> +
> +static const struct atmel_hsmc_reg_layout sama5d2_reg_layout = {
> +     .timing_regs_offset = 0x700,
> +};
> +
> +static const struct of_device_id atmel_smc_ids[] = {
> +     { .compatible = "atmel,at91sam9260-smc", .data = NULL },
> +     { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout },
> +     { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout },
> +     { /* sentinel */ },
> +};
> +
> +/**
> + * atmel_hsmc_get_reg_layout - retrieve the layout of HSMC registers
> + * @np: the HSMC regmap
> + *
> + * Retrieve the layout of HSMC registers.
> + *
> + * Returns NULL in case of SMC, a struct atmel_hsmc_reg_layout pointer
> + * in HSMC case, otherwise ERR_PTR(-EINVAL).
> + */
> +const struct atmel_hsmc_reg_layout *
> +atmel_hsmc_get_reg_layout(struct device_node *np)
> +{
> +     const struct of_device_id *match;
> +
> +     match = of_match_node(atmel_hsmc_ids, np);
> +
> +     return match ? match->data : ERR_PTR(-EINVAL);
> +}
> +EXPORT_SYMBOL_GPL(atmel_hsmc_get_reg_layout);
> diff --git a/drivers/mtd/nand/atmel/nand-controller.c 
> b/drivers/mtd/nand/atmel/nand-controller.c
> index d922a88e407f..29396e618965 100644
> --- a/drivers/mtd/nand/atmel/nand-controller.c
> +++ b/drivers/mtd/nand/atmel/nand-controller.c
> @@ -247,6 +247,7 @@ struct atmel_hsmc_nand_controller {
>               void __iomem *virt;
>               dma_addr_t dma;
>       } sram;
> +     const struct atmel_hsmc_reg_layout *hsmc_layout;
>       struct regmap *io;
>       struct atmel_nfc_op op;
>       struct completion complete;
> @@ -1431,12 +1432,12 @@ static int 
> atmel_hsmc_nand_setup_data_interface(struct atmel_nand *nand,
>                                       int csline,
>                                       const struct nand_data_interface *conf)
>  {
> -     struct atmel_nand_controller *nc;
> +     struct atmel_hsmc_nand_controller *nc;
>       struct atmel_smc_cs_conf smcconf;
>       struct atmel_nand_cs *cs;
>       int ret;
>  
> -     nc = to_nand_controller(nand->base.controller);
> +     nc = to_hsmc_nand_controller(nand->base.controller);
>  
>       ret = atmel_smc_nand_prepare_smcconf(nand, conf, &smcconf);
>       if (ret)
> @@ -1451,7 +1452,8 @@ static int atmel_hsmc_nand_setup_data_interface(struct 
> atmel_nand *nand,
>       if (cs->rb.type == ATMEL_NAND_NATIVE_RB)
>               cs->smcconf.timings |= ATMEL_HSMC_TIMINGS_RBNSEL(cs->rb.id);
>  
> -     atmel_hsmc_cs_conf_apply(nc->smc, cs->id, &cs->smcconf);
> +     atmel_hsmc_cs_conf_apply(nc->base.smc, nc->hsmc_layout, cs->id,
> +                              &cs->smcconf);
>  
>       return 0;
>  }
> @@ -2166,6 +2168,8 @@ atmel_hsmc_nand_controller_init(struct 
> atmel_hsmc_nand_controller *nc)
>               return -EINVAL;
>       }
>  
> +     nc->hsmc_layout = atmel_hsmc_get_reg_layout(np);
> +
>       nc->irq = of_irq_get(np, 0);
>       of_node_put(np);
>       if (nc->irq < 0) {
> diff --git a/include/linux/mfd/syscon/atmel-smc.h 
> b/include/linux/mfd/syscon/atmel-smc.h
> index afa266169800..7a367f34b66a 100644
> --- a/include/linux/mfd/syscon/atmel-smc.h
> +++ b/include/linux/mfd/syscon/atmel-smc.h
> @@ -15,21 +15,26 @@
>  #define _LINUX_MFD_SYSCON_ATMEL_SMC_H_
>  
>  #include <linux/kernel.h>
> +#include <linux/of.h>
>  #include <linux/regmap.h>
>  
>  #define ATMEL_SMC_SETUP(cs)                  (((cs) * 0x10))
> -#define ATMEL_HSMC_SETUP(cs)                 (0x600 + ((cs) * 0x14))
> +#define ATMEL_HSMC_SETUP(layout, cs)         \
> +     ((layout)->timing_regs_offset + ((cs) * 0x14))
>  #define ATMEL_SMC_PULSE(cs)                  (((cs) * 0x10) + 0x4)
> -#define ATMEL_HSMC_PULSE(cs)                 (0x600 + ((cs) * 0x14) + 0x4)
> +#define ATMEL_HSMC_PULSE(layout, cs)         \
> +     ((layout)->timing_regs_offset + ((cs) * 0x14) + 0x4)
>  #define ATMEL_SMC_CYCLE(cs)                  (((cs) * 0x10) + 0x8)
> -#define ATMEL_HSMC_CYCLE(cs)                 (0x600 + ((cs) * 0x14) + 0x8)
> +#define ATMEL_HSMC_CYCLE(layout, cs)                 \
> +     ((layout)->timing_regs_offset + ((cs) * 0x14) + 0x8)
>  #define ATMEL_SMC_NWE_SHIFT                  0
>  #define ATMEL_SMC_NCS_WR_SHIFT                       8
>  #define ATMEL_SMC_NRD_SHIFT                  16
>  #define ATMEL_SMC_NCS_RD_SHIFT                       24
>  
>  #define ATMEL_SMC_MODE(cs)                   (((cs) * 0x10) + 0xc)
> -#define ATMEL_HSMC_MODE(cs)                  (0x600 + ((cs) * 0x14) + 0x10)
> +#define ATMEL_HSMC_MODE(layout, cs)                  \
> +     ((layout)->timing_regs_offset + ((cs) * 0x14) + 0x10)
>  #define ATMEL_SMC_MODE_READMODE_MASK         BIT(0)
>  #define ATMEL_SMC_MODE_READMODE_NCS          (0 << 0)
>  #define ATMEL_SMC_MODE_READMODE_NRD          (1 << 0)
> @@ -59,7 +64,8 @@
>  #define ATMEL_SMC_MODE_PS_16                 (2 << 28)
>  #define ATMEL_SMC_MODE_PS_32                 (3 << 28)
>  
> -#define ATMEL_HSMC_TIMINGS(cs)                       (0x600 + ((cs) * 0x14) 
> + 0xc)
> +#define ATMEL_HSMC_TIMINGS(layout, cs)                       \
> +     ((layout)->timing_regs_offset + ((cs) * 0x14) + 0xc)
>  #define ATMEL_HSMC_TIMINGS_OCMS                      BIT(12)
>  #define ATMEL_HSMC_TIMINGS_RBNSEL(x)         ((x) << 28)
>  #define ATMEL_HSMC_TIMINGS_NFSEL             BIT(31)
> @@ -69,6 +75,10 @@
>  #define ATMEL_HSMC_TIMINGS_TRR_SHIFT         16
>  #define ATMEL_HSMC_TIMINGS_TWB_SHIFT         24
>  
> +struct atmel_hsmc_reg_layout {
> +     unsigned int timing_regs_offset;
> +};
> +
>  /**
>   * struct atmel_smc_cs_conf - SMC CS config as described in the datasheet.
>   * @setup: NCS/NWE/NRD setup timings (not applicable to at91rm9200)
> @@ -98,11 +108,15 @@ int atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf 
> *conf,
>                               unsigned int shift, unsigned int ncycles);
>  void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs,
>                            const struct atmel_smc_cs_conf *conf);
> -void atmel_hsmc_cs_conf_apply(struct regmap *regmap, int cs,
> -                           const struct atmel_smc_cs_conf *conf);
> +void atmel_hsmc_cs_conf_apply(struct regmap *regmap,
> +                           const struct atmel_hsmc_reg_layout *reglayout,
> +                           int cs, const struct atmel_smc_cs_conf *conf);
>  void atmel_smc_cs_conf_get(struct regmap *regmap, int cs,
>                          struct atmel_smc_cs_conf *conf);
> -void atmel_hsmc_cs_conf_get(struct regmap *regmap, int cs,
> -                         struct atmel_smc_cs_conf *conf);
> +void atmel_hsmc_cs_conf_get(struct regmap *regmap,
> +                         const struct atmel_hsmc_reg_layout *reglayout,
> +                         int cs, struct atmel_smc_cs_conf *conf);
> +const struct atmel_hsmc_reg_layout *
> +atmel_hsmc_get_reg_layout(struct device_node *np);
>  
>  #endif /* _LINUX_MFD_SYSCON_ATMEL_SMC_H_ */
> -- 
> 2.12.2
> 

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Reply via email to