[PATCH 2/3] mfd: syscon: atmel-smc: add helper to retrieve register layout

Alexandre Belloni alexandre.belloni at free-electrons.com
Tue Jul 18 02:24:08 PDT 2017


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.brezillon at free-electrons.com>
> Signed-off-by: Ludovic Desroches <ludovic.desroches at microchip.com>
Acked-by: Alexandre Belloni <alexandre.belloni at 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



More information about the linux-arm-kernel mailing list