0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/mfd/syscon/atmel-smc.h>
0012 #include <linux/string.h>
0013
0014
0015
0016
0017
0018
0019
0020 void atmel_smc_cs_conf_init(struct atmel_smc_cs_conf *conf)
0021 {
0022 memset(conf, 0, sizeof(*conf));
0023 }
0024 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_init);
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 static int atmel_smc_cs_encode_ncycles(unsigned int ncycles,
0044 unsigned int msbpos,
0045 unsigned int msbwidth,
0046 unsigned int msbfactor,
0047 unsigned int *encodedval)
0048 {
0049 unsigned int lsbmask = GENMASK(msbpos - 1, 0);
0050 unsigned int msbmask = GENMASK(msbwidth - 1, 0);
0051 unsigned int msb, lsb;
0052 int ret = 0;
0053
0054 msb = ncycles / msbfactor;
0055 lsb = ncycles % msbfactor;
0056
0057 if (lsb > lsbmask) {
0058 lsb = 0;
0059 msb++;
0060 }
0061
0062
0063
0064
0065
0066
0067 if (msb > msbmask) {
0068 msb = msbmask;
0069 lsb = lsbmask;
0070 ret = -ERANGE;
0071 }
0072
0073 *encodedval = (msb << msbpos) | lsb;
0074
0075 return ret;
0076 }
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093 int atmel_smc_cs_conf_set_timing(struct atmel_smc_cs_conf *conf,
0094 unsigned int shift, unsigned int ncycles)
0095 {
0096 unsigned int val;
0097 int ret;
0098
0099 if (shift != ATMEL_HSMC_TIMINGS_TCLR_SHIFT &&
0100 shift != ATMEL_HSMC_TIMINGS_TADL_SHIFT &&
0101 shift != ATMEL_HSMC_TIMINGS_TAR_SHIFT &&
0102 shift != ATMEL_HSMC_TIMINGS_TRR_SHIFT &&
0103 shift != ATMEL_HSMC_TIMINGS_TWB_SHIFT)
0104 return -EINVAL;
0105
0106
0107
0108
0109
0110
0111
0112 ret = atmel_smc_cs_encode_ncycles(ncycles, 3, 1, 64, &val);
0113 conf->timings &= ~GENMASK(shift + 3, shift);
0114 conf->timings |= val << shift;
0115
0116 return ret;
0117 }
0118 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_timing);
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135 int atmel_smc_cs_conf_set_setup(struct atmel_smc_cs_conf *conf,
0136 unsigned int shift, unsigned int ncycles)
0137 {
0138 unsigned int val;
0139 int ret;
0140
0141 if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
0142 shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
0143 return -EINVAL;
0144
0145
0146
0147
0148
0149
0150
0151 ret = atmel_smc_cs_encode_ncycles(ncycles, 5, 1, 128, &val);
0152 conf->setup &= ~GENMASK(shift + 7, shift);
0153 conf->setup |= val << shift;
0154
0155 return ret;
0156 }
0157 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_setup);
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174 int atmel_smc_cs_conf_set_pulse(struct atmel_smc_cs_conf *conf,
0175 unsigned int shift, unsigned int ncycles)
0176 {
0177 unsigned int val;
0178 int ret;
0179
0180 if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
0181 shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
0182 return -EINVAL;
0183
0184
0185
0186
0187
0188
0189
0190 ret = atmel_smc_cs_encode_ncycles(ncycles, 6, 1, 256, &val);
0191 conf->pulse &= ~GENMASK(shift + 7, shift);
0192 conf->pulse |= val << shift;
0193
0194 return ret;
0195 }
0196 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_pulse);
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213 int atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf *conf,
0214 unsigned int shift, unsigned int ncycles)
0215 {
0216 unsigned int val;
0217 int ret;
0218
0219 if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NRD_SHIFT)
0220 return -EINVAL;
0221
0222
0223
0224
0225
0226
0227
0228 ret = atmel_smc_cs_encode_ncycles(ncycles, 7, 2, 256, &val);
0229 conf->cycle &= ~GENMASK(shift + 15, shift);
0230 conf->cycle |= val << shift;
0231
0232 return ret;
0233 }
0234 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle);
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs,
0246 const struct atmel_smc_cs_conf *conf)
0247 {
0248 regmap_write(regmap, ATMEL_SMC_SETUP(cs), conf->setup);
0249 regmap_write(regmap, ATMEL_SMC_PULSE(cs), conf->pulse);
0250 regmap_write(regmap, ATMEL_SMC_CYCLE(cs), conf->cycle);
0251 regmap_write(regmap, ATMEL_SMC_MODE(cs), conf->mode);
0252 }
0253 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply);
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 void atmel_hsmc_cs_conf_apply(struct regmap *regmap,
0266 const struct atmel_hsmc_reg_layout *layout,
0267 int cs, const struct atmel_smc_cs_conf *conf)
0268 {
0269 regmap_write(regmap, ATMEL_HSMC_SETUP(layout, cs), conf->setup);
0270 regmap_write(regmap, ATMEL_HSMC_PULSE(layout, cs), conf->pulse);
0271 regmap_write(regmap, ATMEL_HSMC_CYCLE(layout, cs), conf->cycle);
0272 regmap_write(regmap, ATMEL_HSMC_TIMINGS(layout, cs), conf->timings);
0273 regmap_write(regmap, ATMEL_HSMC_MODE(layout, cs), conf->mode);
0274 }
0275 EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply);
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286 void atmel_smc_cs_conf_get(struct regmap *regmap, int cs,
0287 struct atmel_smc_cs_conf *conf)
0288 {
0289 regmap_read(regmap, ATMEL_SMC_SETUP(cs), &conf->setup);
0290 regmap_read(regmap, ATMEL_SMC_PULSE(cs), &conf->pulse);
0291 regmap_read(regmap, ATMEL_SMC_CYCLE(cs), &conf->cycle);
0292 regmap_read(regmap, ATMEL_SMC_MODE(cs), &conf->mode);
0293 }
0294 EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get);
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306 void atmel_hsmc_cs_conf_get(struct regmap *regmap,
0307 const struct atmel_hsmc_reg_layout *layout,
0308 int cs, struct atmel_smc_cs_conf *conf)
0309 {
0310 regmap_read(regmap, ATMEL_HSMC_SETUP(layout, cs), &conf->setup);
0311 regmap_read(regmap, ATMEL_HSMC_PULSE(layout, cs), &conf->pulse);
0312 regmap_read(regmap, ATMEL_HSMC_CYCLE(layout, cs), &conf->cycle);
0313 regmap_read(regmap, ATMEL_HSMC_TIMINGS(layout, cs), &conf->timings);
0314 regmap_read(regmap, ATMEL_HSMC_MODE(layout, cs), &conf->mode);
0315 }
0316 EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get);
0317
0318 static const struct atmel_hsmc_reg_layout sama5d3_reg_layout = {
0319 .timing_regs_offset = 0x600,
0320 };
0321
0322 static const struct atmel_hsmc_reg_layout sama5d2_reg_layout = {
0323 .timing_regs_offset = 0x700,
0324 };
0325
0326 static const struct of_device_id atmel_smc_ids[] = {
0327 { .compatible = "atmel,at91sam9260-smc", .data = NULL },
0328 { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout },
0329 { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout },
0330 { },
0331 };
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342 const struct atmel_hsmc_reg_layout *
0343 atmel_hsmc_get_reg_layout(struct device_node *np)
0344 {
0345 const struct of_device_id *match;
0346
0347 match = of_match_node(atmel_smc_ids, np);
0348
0349 return match ? match->data : ERR_PTR(-EINVAL);
0350 }
0351 EXPORT_SYMBOL_GPL(atmel_hsmc_get_reg_layout);