root/drivers/mfd/atmel-smc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. atmel_smc_cs_conf_init
  2. atmel_smc_cs_encode_ncycles
  3. atmel_smc_cs_conf_set_timing
  4. atmel_smc_cs_conf_set_setup
  5. atmel_smc_cs_conf_set_pulse
  6. atmel_smc_cs_conf_set_cycle
  7. atmel_smc_cs_conf_apply
  8. atmel_hsmc_cs_conf_apply
  9. atmel_smc_cs_conf_get
  10. atmel_hsmc_cs_conf_get
  11. atmel_hsmc_get_reg_layout

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Atmel SMC (Static Memory Controller) helper functions.
   4  *
   5  * Copyright (C) 2017 Atmel
   6  * Copyright (C) 2017 Free Electrons
   7  *
   8  * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
   9  */
  10 
  11 #include <linux/mfd/syscon/atmel-smc.h>
  12 #include <linux/string.h>
  13 
  14 /**
  15  * atmel_smc_cs_conf_init - initialize a SMC CS conf
  16  * @conf: the SMC CS conf to initialize
  17  *
  18  * Set all fields to 0 so that one can start defining a new config.
  19  */
  20 void atmel_smc_cs_conf_init(struct atmel_smc_cs_conf *conf)
  21 {
  22         memset(conf, 0, sizeof(*conf));
  23 }
  24 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_init);
  25 
  26 /**
  27  * atmel_smc_cs_encode_ncycles - encode a number of MCK clk cycles in the
  28  *                               format expected by the SMC engine
  29  * @ncycles: number of MCK clk cycles
  30  * @msbpos: position of the MSB part of the timing field
  31  * @msbwidth: width of the MSB part of the timing field
  32  * @msbfactor: factor applied to the MSB
  33  * @encodedval: param used to store the encoding result
  34  *
  35  * This function encodes the @ncycles value as described in the datasheet
  36  * (section "SMC Setup/Pulse/Cycle/Timings Register"). This is a generic
  37  * helper which called with different parameter depending on the encoding
  38  * scheme.
  39  *
  40  * If the @ncycles value is too big to be encoded, -ERANGE is returned and
  41  * the encodedval is contains the maximum val. Otherwise, 0 is returned.
  42  */
  43 static int atmel_smc_cs_encode_ncycles(unsigned int ncycles,
  44                                        unsigned int msbpos,
  45                                        unsigned int msbwidth,
  46                                        unsigned int msbfactor,
  47                                        unsigned int *encodedval)
  48 {
  49         unsigned int lsbmask = GENMASK(msbpos - 1, 0);
  50         unsigned int msbmask = GENMASK(msbwidth - 1, 0);
  51         unsigned int msb, lsb;
  52         int ret = 0;
  53 
  54         msb = ncycles / msbfactor;
  55         lsb = ncycles % msbfactor;
  56 
  57         if (lsb > lsbmask) {
  58                 lsb = 0;
  59                 msb++;
  60         }
  61 
  62         /*
  63          * Let's just put the maximum we can if the requested setting does
  64          * not fit in the register field.
  65          * We still return -ERANGE in case the caller cares.
  66          */
  67         if (msb > msbmask) {
  68                 msb = msbmask;
  69                 lsb = lsbmask;
  70                 ret = -ERANGE;
  71         }
  72 
  73         *encodedval = (msb << msbpos) | lsb;
  74 
  75         return ret;
  76 }
  77 
  78 /**
  79  * atmel_smc_cs_conf_set_timing - set the SMC CS conf Txx parameter to a
  80  *                                specific value
  81  * @conf: SMC CS conf descriptor
  82  * @shift: the position of the Txx field in the TIMINGS register
  83  * @ncycles: value (expressed in MCK clk cycles) to assign to this Txx
  84  *           parameter
  85  *
  86  * This function encodes the @ncycles value as described in the datasheet
  87  * (section "SMC Timings Register"), and then stores the result in the
  88  * @conf->timings field at @shift position.
  89  *
  90  * Returns -EINVAL if shift is invalid, -ERANGE if ncycles does not fit in
  91  * the field, and 0 otherwise.
  92  */
  93 int atmel_smc_cs_conf_set_timing(struct atmel_smc_cs_conf *conf,
  94                                  unsigned int shift, unsigned int ncycles)
  95 {
  96         unsigned int val;
  97         int ret;
  98 
  99         if (shift != ATMEL_HSMC_TIMINGS_TCLR_SHIFT &&
 100             shift != ATMEL_HSMC_TIMINGS_TADL_SHIFT &&
 101             shift != ATMEL_HSMC_TIMINGS_TAR_SHIFT &&
 102             shift != ATMEL_HSMC_TIMINGS_TRR_SHIFT &&
 103             shift != ATMEL_HSMC_TIMINGS_TWB_SHIFT)
 104                 return -EINVAL;
 105 
 106         /*
 107          * The formula described in atmel datasheets (section "HSMC Timings
 108          * Register"):
 109          *
 110          * ncycles = (Txx[3] * 64) + Txx[2:0]
 111          */
 112         ret = atmel_smc_cs_encode_ncycles(ncycles, 3, 1, 64, &val);
 113         conf->timings &= ~GENMASK(shift + 3, shift);
 114         conf->timings |= val << shift;
 115 
 116         return ret;
 117 }
 118 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_timing);
 119 
 120 /**
 121  * atmel_smc_cs_conf_set_setup - set the SMC CS conf xx_SETUP parameter to a
 122  *                               specific value
 123  * @conf: SMC CS conf descriptor
 124  * @shift: the position of the xx_SETUP field in the SETUP register
 125  * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_SETUP
 126  *           parameter
 127  *
 128  * This function encodes the @ncycles value as described in the datasheet
 129  * (section "SMC Setup Register"), and then stores the result in the
 130  * @conf->setup field at @shift position.
 131  *
 132  * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
 133  * the field, and 0 otherwise.
 134  */
 135 int atmel_smc_cs_conf_set_setup(struct atmel_smc_cs_conf *conf,
 136                                 unsigned int shift, unsigned int ncycles)
 137 {
 138         unsigned int val;
 139         int ret;
 140 
 141         if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
 142             shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
 143                 return -EINVAL;
 144 
 145         /*
 146          * The formula described in atmel datasheets (section "SMC Setup
 147          * Register"):
 148          *
 149          * ncycles = (128 * xx_SETUP[5]) + xx_SETUP[4:0]
 150          */
 151         ret = atmel_smc_cs_encode_ncycles(ncycles, 5, 1, 128, &val);
 152         conf->setup &= ~GENMASK(shift + 7, shift);
 153         conf->setup |= val << shift;
 154 
 155         return ret;
 156 }
 157 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_setup);
 158 
 159 /**
 160  * atmel_smc_cs_conf_set_pulse - set the SMC CS conf xx_PULSE parameter to a
 161  *                               specific value
 162  * @conf: SMC CS conf descriptor
 163  * @shift: the position of the xx_PULSE field in the PULSE register
 164  * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_PULSE
 165  *           parameter
 166  *
 167  * This function encodes the @ncycles value as described in the datasheet
 168  * (section "SMC Pulse Register"), and then stores the result in the
 169  * @conf->setup field at @shift position.
 170  *
 171  * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
 172  * the field, and 0 otherwise.
 173  */
 174 int atmel_smc_cs_conf_set_pulse(struct atmel_smc_cs_conf *conf,
 175                                 unsigned int shift, unsigned int ncycles)
 176 {
 177         unsigned int val;
 178         int ret;
 179 
 180         if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
 181             shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
 182                 return -EINVAL;
 183 
 184         /*
 185          * The formula described in atmel datasheets (section "SMC Pulse
 186          * Register"):
 187          *
 188          * ncycles = (256 * xx_PULSE[6]) + xx_PULSE[5:0]
 189          */
 190         ret = atmel_smc_cs_encode_ncycles(ncycles, 6, 1, 256, &val);
 191         conf->pulse &= ~GENMASK(shift + 7, shift);
 192         conf->pulse |= val << shift;
 193 
 194         return ret;
 195 }
 196 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_pulse);
 197 
 198 /**
 199  * atmel_smc_cs_conf_set_cycle - set the SMC CS conf xx_CYCLE parameter to a
 200  *                               specific value
 201  * @conf: SMC CS conf descriptor
 202  * @shift: the position of the xx_CYCLE field in the CYCLE register
 203  * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_CYCLE
 204  *           parameter
 205  *
 206  * This function encodes the @ncycles value as described in the datasheet
 207  * (section "SMC Cycle Register"), and then stores the result in the
 208  * @conf->setup field at @shift position.
 209  *
 210  * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
 211  * the field, and 0 otherwise.
 212  */
 213 int atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf *conf,
 214                                 unsigned int shift, unsigned int ncycles)
 215 {
 216         unsigned int val;
 217         int ret;
 218 
 219         if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NRD_SHIFT)
 220                 return -EINVAL;
 221 
 222         /*
 223          * The formula described in atmel datasheets (section "SMC Cycle
 224          * Register"):
 225          *
 226          * ncycles = (xx_CYCLE[8:7] * 256) + xx_CYCLE[6:0]
 227          */
 228         ret = atmel_smc_cs_encode_ncycles(ncycles, 7, 2, 256, &val);
 229         conf->cycle &= ~GENMASK(shift + 15, shift);
 230         conf->cycle |= val << shift;
 231 
 232         return ret;
 233 }
 234 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle);
 235 
 236 /**
 237  * atmel_smc_cs_conf_apply - apply an SMC CS conf
 238  * @regmap: the SMC regmap
 239  * @cs: the CS id
 240  * @conf the SMC CS conf to apply
 241  *
 242  * Applies an SMC CS configuration.
 243  * Only valid on at91sam9/avr32 SoCs.
 244  */
 245 void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs,
 246                              const struct atmel_smc_cs_conf *conf)
 247 {
 248         regmap_write(regmap, ATMEL_SMC_SETUP(cs), conf->setup);
 249         regmap_write(regmap, ATMEL_SMC_PULSE(cs), conf->pulse);
 250         regmap_write(regmap, ATMEL_SMC_CYCLE(cs), conf->cycle);
 251         regmap_write(regmap, ATMEL_SMC_MODE(cs), conf->mode);
 252 }
 253 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply);
 254 
 255 /**
 256  * atmel_hsmc_cs_conf_apply - apply an SMC CS conf
 257  * @regmap: the HSMC regmap
 258  * @cs: the CS id
 259  * @layout: the layout of registers
 260  * @conf the SMC CS conf to apply
 261  *
 262  * Applies an SMC CS configuration.
 263  * Only valid on post-sama5 SoCs.
 264  */
 265 void atmel_hsmc_cs_conf_apply(struct regmap *regmap,
 266                               const struct atmel_hsmc_reg_layout *layout,
 267                               int cs, const struct atmel_smc_cs_conf *conf)
 268 {
 269         regmap_write(regmap, ATMEL_HSMC_SETUP(layout, cs), conf->setup);
 270         regmap_write(regmap, ATMEL_HSMC_PULSE(layout, cs), conf->pulse);
 271         regmap_write(regmap, ATMEL_HSMC_CYCLE(layout, cs), conf->cycle);
 272         regmap_write(regmap, ATMEL_HSMC_TIMINGS(layout, cs), conf->timings);
 273         regmap_write(regmap, ATMEL_HSMC_MODE(layout, cs), conf->mode);
 274 }
 275 EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply);
 276 
 277 /**
 278  * atmel_smc_cs_conf_get - retrieve the current SMC CS conf
 279  * @regmap: the SMC regmap
 280  * @cs: the CS id
 281  * @conf: the SMC CS conf object to store the current conf
 282  *
 283  * Retrieve the SMC CS configuration.
 284  * Only valid on at91sam9/avr32 SoCs.
 285  */
 286 void atmel_smc_cs_conf_get(struct regmap *regmap, int cs,
 287                            struct atmel_smc_cs_conf *conf)
 288 {
 289         regmap_read(regmap, ATMEL_SMC_SETUP(cs), &conf->setup);
 290         regmap_read(regmap, ATMEL_SMC_PULSE(cs), &conf->pulse);
 291         regmap_read(regmap, ATMEL_SMC_CYCLE(cs), &conf->cycle);
 292         regmap_read(regmap, ATMEL_SMC_MODE(cs), &conf->mode);
 293 }
 294 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get);
 295 
 296 /**
 297  * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf
 298  * @regmap: the HSMC regmap
 299  * @cs: the CS id
 300  * @layout: the layout of registers
 301  * @conf: the SMC CS conf object to store the current conf
 302  *
 303  * Retrieve the SMC CS configuration.
 304  * Only valid on post-sama5 SoCs.
 305  */
 306 void atmel_hsmc_cs_conf_get(struct regmap *regmap,
 307                             const struct atmel_hsmc_reg_layout *layout,
 308                             int cs, struct atmel_smc_cs_conf *conf)
 309 {
 310         regmap_read(regmap, ATMEL_HSMC_SETUP(layout, cs), &conf->setup);
 311         regmap_read(regmap, ATMEL_HSMC_PULSE(layout, cs), &conf->pulse);
 312         regmap_read(regmap, ATMEL_HSMC_CYCLE(layout, cs), &conf->cycle);
 313         regmap_read(regmap, ATMEL_HSMC_TIMINGS(layout, cs), &conf->timings);
 314         regmap_read(regmap, ATMEL_HSMC_MODE(layout, cs), &conf->mode);
 315 }
 316 EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get);
 317 
 318 static const struct atmel_hsmc_reg_layout sama5d3_reg_layout = {
 319         .timing_regs_offset = 0x600,
 320 };
 321 
 322 static const struct atmel_hsmc_reg_layout sama5d2_reg_layout = {
 323         .timing_regs_offset = 0x700,
 324 };
 325 
 326 static const struct of_device_id atmel_smc_ids[] = {
 327         { .compatible = "atmel,at91sam9260-smc", .data = NULL },
 328         { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout },
 329         { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout },
 330         { /* sentinel */ },
 331 };
 332 
 333 /**
 334  * atmel_hsmc_get_reg_layout - retrieve the layout of HSMC registers
 335  * @np: the HSMC regmap
 336  *
 337  * Retrieve the layout of HSMC registers.
 338  *
 339  * Returns NULL in case of SMC, a struct atmel_hsmc_reg_layout pointer
 340  * in HSMC case, otherwise ERR_PTR(-EINVAL).
 341  */
 342 const struct atmel_hsmc_reg_layout *
 343 atmel_hsmc_get_reg_layout(struct device_node *np)
 344 {
 345         const struct of_device_id *match;
 346 
 347         match = of_match_node(atmel_smc_ids, np);
 348 
 349         return match ? match->data : ERR_PTR(-EINVAL);
 350 }
 351 EXPORT_SYMBOL_GPL(atmel_hsmc_get_reg_layout);

/* [<][>][^][v][top][bottom][index][help] */