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