18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Atmel SMC (Static Memory Controller) helper functions. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 Atmel 68c2ecf20Sopenharmony_ci * Copyright (C) 2017 Free Electrons 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/mfd/syscon/atmel-smc.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/** 158c2ecf20Sopenharmony_ci * atmel_smc_cs_conf_init - initialize a SMC CS conf 168c2ecf20Sopenharmony_ci * @conf: the SMC CS conf to initialize 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Set all fields to 0 so that one can start defining a new config. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_civoid atmel_smc_cs_conf_init(struct atmel_smc_cs_conf *conf) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci memset(conf, 0, sizeof(*conf)); 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_smc_cs_conf_init); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/** 278c2ecf20Sopenharmony_ci * atmel_smc_cs_encode_ncycles - encode a number of MCK clk cycles in the 288c2ecf20Sopenharmony_ci * format expected by the SMC engine 298c2ecf20Sopenharmony_ci * @ncycles: number of MCK clk cycles 308c2ecf20Sopenharmony_ci * @msbpos: position of the MSB part of the timing field 318c2ecf20Sopenharmony_ci * @msbwidth: width of the MSB part of the timing field 328c2ecf20Sopenharmony_ci * @msbfactor: factor applied to the MSB 338c2ecf20Sopenharmony_ci * @encodedval: param used to store the encoding result 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * This function encodes the @ncycles value as described in the datasheet 368c2ecf20Sopenharmony_ci * (section "SMC Setup/Pulse/Cycle/Timings Register"). This is a generic 378c2ecf20Sopenharmony_ci * helper which called with different parameter depending on the encoding 388c2ecf20Sopenharmony_ci * scheme. 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * If the @ncycles value is too big to be encoded, -ERANGE is returned and 418c2ecf20Sopenharmony_ci * the encodedval is contains the maximum val. Otherwise, 0 is returned. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_cistatic int atmel_smc_cs_encode_ncycles(unsigned int ncycles, 448c2ecf20Sopenharmony_ci unsigned int msbpos, 458c2ecf20Sopenharmony_ci unsigned int msbwidth, 468c2ecf20Sopenharmony_ci unsigned int msbfactor, 478c2ecf20Sopenharmony_ci unsigned int *encodedval) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci unsigned int lsbmask = GENMASK(msbpos - 1, 0); 508c2ecf20Sopenharmony_ci unsigned int msbmask = GENMASK(msbwidth - 1, 0); 518c2ecf20Sopenharmony_ci unsigned int msb, lsb; 528c2ecf20Sopenharmony_ci int ret = 0; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci msb = ncycles / msbfactor; 558c2ecf20Sopenharmony_ci lsb = ncycles % msbfactor; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (lsb > lsbmask) { 588c2ecf20Sopenharmony_ci lsb = 0; 598c2ecf20Sopenharmony_ci msb++; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* 638c2ecf20Sopenharmony_ci * Let's just put the maximum we can if the requested setting does 648c2ecf20Sopenharmony_ci * not fit in the register field. 658c2ecf20Sopenharmony_ci * We still return -ERANGE in case the caller cares. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci if (msb > msbmask) { 688c2ecf20Sopenharmony_ci msb = msbmask; 698c2ecf20Sopenharmony_ci lsb = lsbmask; 708c2ecf20Sopenharmony_ci ret = -ERANGE; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci *encodedval = (msb << msbpos) | lsb; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return ret; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/** 798c2ecf20Sopenharmony_ci * atmel_smc_cs_conf_set_timing - set the SMC CS conf Txx parameter to a 808c2ecf20Sopenharmony_ci * specific value 818c2ecf20Sopenharmony_ci * @conf: SMC CS conf descriptor 828c2ecf20Sopenharmony_ci * @shift: the position of the Txx field in the TIMINGS register 838c2ecf20Sopenharmony_ci * @ncycles: value (expressed in MCK clk cycles) to assign to this Txx 848c2ecf20Sopenharmony_ci * parameter 858c2ecf20Sopenharmony_ci * 868c2ecf20Sopenharmony_ci * This function encodes the @ncycles value as described in the datasheet 878c2ecf20Sopenharmony_ci * (section "SMC Timings Register"), and then stores the result in the 888c2ecf20Sopenharmony_ci * @conf->timings field at @shift position. 898c2ecf20Sopenharmony_ci * 908c2ecf20Sopenharmony_ci * Returns -EINVAL if shift is invalid, -ERANGE if ncycles does not fit in 918c2ecf20Sopenharmony_ci * the field, and 0 otherwise. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ciint atmel_smc_cs_conf_set_timing(struct atmel_smc_cs_conf *conf, 948c2ecf20Sopenharmony_ci unsigned int shift, unsigned int ncycles) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci unsigned int val; 978c2ecf20Sopenharmony_ci int ret; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (shift != ATMEL_HSMC_TIMINGS_TCLR_SHIFT && 1008c2ecf20Sopenharmony_ci shift != ATMEL_HSMC_TIMINGS_TADL_SHIFT && 1018c2ecf20Sopenharmony_ci shift != ATMEL_HSMC_TIMINGS_TAR_SHIFT && 1028c2ecf20Sopenharmony_ci shift != ATMEL_HSMC_TIMINGS_TRR_SHIFT && 1038c2ecf20Sopenharmony_ci shift != ATMEL_HSMC_TIMINGS_TWB_SHIFT) 1048c2ecf20Sopenharmony_ci return -EINVAL; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * The formula described in atmel datasheets (section "HSMC Timings 1088c2ecf20Sopenharmony_ci * Register"): 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * ncycles = (Txx[3] * 64) + Txx[2:0] 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci ret = atmel_smc_cs_encode_ncycles(ncycles, 3, 1, 64, &val); 1138c2ecf20Sopenharmony_ci conf->timings &= ~GENMASK(shift + 3, shift); 1148c2ecf20Sopenharmony_ci conf->timings |= val << shift; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return ret; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_timing); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/** 1218c2ecf20Sopenharmony_ci * atmel_smc_cs_conf_set_setup - set the SMC CS conf xx_SETUP parameter to a 1228c2ecf20Sopenharmony_ci * specific value 1238c2ecf20Sopenharmony_ci * @conf: SMC CS conf descriptor 1248c2ecf20Sopenharmony_ci * @shift: the position of the xx_SETUP field in the SETUP register 1258c2ecf20Sopenharmony_ci * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_SETUP 1268c2ecf20Sopenharmony_ci * parameter 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * This function encodes the @ncycles value as described in the datasheet 1298c2ecf20Sopenharmony_ci * (section "SMC Setup Register"), and then stores the result in the 1308c2ecf20Sopenharmony_ci * @conf->setup field at @shift position. 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in 1338c2ecf20Sopenharmony_ci * the field, and 0 otherwise. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ciint atmel_smc_cs_conf_set_setup(struct atmel_smc_cs_conf *conf, 1368c2ecf20Sopenharmony_ci unsigned int shift, unsigned int ncycles) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci unsigned int val; 1398c2ecf20Sopenharmony_ci int ret; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT && 1428c2ecf20Sopenharmony_ci shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT) 1438c2ecf20Sopenharmony_ci return -EINVAL; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * The formula described in atmel datasheets (section "SMC Setup 1478c2ecf20Sopenharmony_ci * Register"): 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * ncycles = (128 * xx_SETUP[5]) + xx_SETUP[4:0] 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci ret = atmel_smc_cs_encode_ncycles(ncycles, 5, 1, 128, &val); 1528c2ecf20Sopenharmony_ci conf->setup &= ~GENMASK(shift + 7, shift); 1538c2ecf20Sopenharmony_ci conf->setup |= val << shift; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return ret; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_setup); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/** 1608c2ecf20Sopenharmony_ci * atmel_smc_cs_conf_set_pulse - set the SMC CS conf xx_PULSE parameter to a 1618c2ecf20Sopenharmony_ci * specific value 1628c2ecf20Sopenharmony_ci * @conf: SMC CS conf descriptor 1638c2ecf20Sopenharmony_ci * @shift: the position of the xx_PULSE field in the PULSE register 1648c2ecf20Sopenharmony_ci * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_PULSE 1658c2ecf20Sopenharmony_ci * parameter 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * This function encodes the @ncycles value as described in the datasheet 1688c2ecf20Sopenharmony_ci * (section "SMC Pulse Register"), and then stores the result in the 1698c2ecf20Sopenharmony_ci * @conf->setup field at @shift position. 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in 1728c2ecf20Sopenharmony_ci * the field, and 0 otherwise. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ciint atmel_smc_cs_conf_set_pulse(struct atmel_smc_cs_conf *conf, 1758c2ecf20Sopenharmony_ci unsigned int shift, unsigned int ncycles) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci unsigned int val; 1788c2ecf20Sopenharmony_ci int ret; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT && 1818c2ecf20Sopenharmony_ci shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT) 1828c2ecf20Sopenharmony_ci return -EINVAL; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* 1858c2ecf20Sopenharmony_ci * The formula described in atmel datasheets (section "SMC Pulse 1868c2ecf20Sopenharmony_ci * Register"): 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * ncycles = (256 * xx_PULSE[6]) + xx_PULSE[5:0] 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci ret = atmel_smc_cs_encode_ncycles(ncycles, 6, 1, 256, &val); 1918c2ecf20Sopenharmony_ci conf->pulse &= ~GENMASK(shift + 7, shift); 1928c2ecf20Sopenharmony_ci conf->pulse |= val << shift; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return ret; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_pulse); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/** 1998c2ecf20Sopenharmony_ci * atmel_smc_cs_conf_set_cycle - set the SMC CS conf xx_CYCLE parameter to a 2008c2ecf20Sopenharmony_ci * specific value 2018c2ecf20Sopenharmony_ci * @conf: SMC CS conf descriptor 2028c2ecf20Sopenharmony_ci * @shift: the position of the xx_CYCLE field in the CYCLE register 2038c2ecf20Sopenharmony_ci * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_CYCLE 2048c2ecf20Sopenharmony_ci * parameter 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * This function encodes the @ncycles value as described in the datasheet 2078c2ecf20Sopenharmony_ci * (section "SMC Cycle Register"), and then stores the result in the 2088c2ecf20Sopenharmony_ci * @conf->setup field at @shift position. 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in 2118c2ecf20Sopenharmony_ci * the field, and 0 otherwise. 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ciint atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf *conf, 2148c2ecf20Sopenharmony_ci unsigned int shift, unsigned int ncycles) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci unsigned int val; 2178c2ecf20Sopenharmony_ci int ret; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NRD_SHIFT) 2208c2ecf20Sopenharmony_ci return -EINVAL; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* 2238c2ecf20Sopenharmony_ci * The formula described in atmel datasheets (section "SMC Cycle 2248c2ecf20Sopenharmony_ci * Register"): 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * ncycles = (xx_CYCLE[8:7] * 256) + xx_CYCLE[6:0] 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci ret = atmel_smc_cs_encode_ncycles(ncycles, 7, 2, 256, &val); 2298c2ecf20Sopenharmony_ci conf->cycle &= ~GENMASK(shift + 15, shift); 2308c2ecf20Sopenharmony_ci conf->cycle |= val << shift; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci/** 2378c2ecf20Sopenharmony_ci * atmel_smc_cs_conf_apply - apply an SMC CS conf 2388c2ecf20Sopenharmony_ci * @regmap: the SMC regmap 2398c2ecf20Sopenharmony_ci * @cs: the CS id 2408c2ecf20Sopenharmony_ci * @conf: the SMC CS conf to apply 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * Applies an SMC CS configuration. 2438c2ecf20Sopenharmony_ci * Only valid on at91sam9/avr32 SoCs. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_civoid atmel_smc_cs_conf_apply(struct regmap *regmap, int cs, 2468c2ecf20Sopenharmony_ci const struct atmel_smc_cs_conf *conf) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci regmap_write(regmap, ATMEL_SMC_SETUP(cs), conf->setup); 2498c2ecf20Sopenharmony_ci regmap_write(regmap, ATMEL_SMC_PULSE(cs), conf->pulse); 2508c2ecf20Sopenharmony_ci regmap_write(regmap, ATMEL_SMC_CYCLE(cs), conf->cycle); 2518c2ecf20Sopenharmony_ci regmap_write(regmap, ATMEL_SMC_MODE(cs), conf->mode); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/** 2568c2ecf20Sopenharmony_ci * atmel_hsmc_cs_conf_apply - apply an SMC CS conf 2578c2ecf20Sopenharmony_ci * @regmap: the HSMC regmap 2588c2ecf20Sopenharmony_ci * @cs: the CS id 2598c2ecf20Sopenharmony_ci * @layout: the layout of registers 2608c2ecf20Sopenharmony_ci * @conf: the SMC CS conf to apply 2618c2ecf20Sopenharmony_ci * 2628c2ecf20Sopenharmony_ci * Applies an SMC CS configuration. 2638c2ecf20Sopenharmony_ci * Only valid on post-sama5 SoCs. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_civoid atmel_hsmc_cs_conf_apply(struct regmap *regmap, 2668c2ecf20Sopenharmony_ci const struct atmel_hsmc_reg_layout *layout, 2678c2ecf20Sopenharmony_ci int cs, const struct atmel_smc_cs_conf *conf) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci regmap_write(regmap, ATMEL_HSMC_SETUP(layout, cs), conf->setup); 2708c2ecf20Sopenharmony_ci regmap_write(regmap, ATMEL_HSMC_PULSE(layout, cs), conf->pulse); 2718c2ecf20Sopenharmony_ci regmap_write(regmap, ATMEL_HSMC_CYCLE(layout, cs), conf->cycle); 2728c2ecf20Sopenharmony_ci regmap_write(regmap, ATMEL_HSMC_TIMINGS(layout, cs), conf->timings); 2738c2ecf20Sopenharmony_ci regmap_write(regmap, ATMEL_HSMC_MODE(layout, cs), conf->mode); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/** 2788c2ecf20Sopenharmony_ci * atmel_smc_cs_conf_get - retrieve the current SMC CS conf 2798c2ecf20Sopenharmony_ci * @regmap: the SMC regmap 2808c2ecf20Sopenharmony_ci * @cs: the CS id 2818c2ecf20Sopenharmony_ci * @conf: the SMC CS conf object to store the current conf 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * Retrieve the SMC CS configuration. 2848c2ecf20Sopenharmony_ci * Only valid on at91sam9/avr32 SoCs. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_civoid atmel_smc_cs_conf_get(struct regmap *regmap, int cs, 2878c2ecf20Sopenharmony_ci struct atmel_smc_cs_conf *conf) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci regmap_read(regmap, ATMEL_SMC_SETUP(cs), &conf->setup); 2908c2ecf20Sopenharmony_ci regmap_read(regmap, ATMEL_SMC_PULSE(cs), &conf->pulse); 2918c2ecf20Sopenharmony_ci regmap_read(regmap, ATMEL_SMC_CYCLE(cs), &conf->cycle); 2928c2ecf20Sopenharmony_ci regmap_read(regmap, ATMEL_SMC_MODE(cs), &conf->mode); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/** 2978c2ecf20Sopenharmony_ci * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf 2988c2ecf20Sopenharmony_ci * @regmap: the HSMC regmap 2998c2ecf20Sopenharmony_ci * @cs: the CS id 3008c2ecf20Sopenharmony_ci * @layout: the layout of registers 3018c2ecf20Sopenharmony_ci * @conf: the SMC CS conf object to store the current conf 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci * Retrieve the SMC CS configuration. 3048c2ecf20Sopenharmony_ci * Only valid on post-sama5 SoCs. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_civoid atmel_hsmc_cs_conf_get(struct regmap *regmap, 3078c2ecf20Sopenharmony_ci const struct atmel_hsmc_reg_layout *layout, 3088c2ecf20Sopenharmony_ci int cs, struct atmel_smc_cs_conf *conf) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci regmap_read(regmap, ATMEL_HSMC_SETUP(layout, cs), &conf->setup); 3118c2ecf20Sopenharmony_ci regmap_read(regmap, ATMEL_HSMC_PULSE(layout, cs), &conf->pulse); 3128c2ecf20Sopenharmony_ci regmap_read(regmap, ATMEL_HSMC_CYCLE(layout, cs), &conf->cycle); 3138c2ecf20Sopenharmony_ci regmap_read(regmap, ATMEL_HSMC_TIMINGS(layout, cs), &conf->timings); 3148c2ecf20Sopenharmony_ci regmap_read(regmap, ATMEL_HSMC_MODE(layout, cs), &conf->mode); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic const struct atmel_hsmc_reg_layout sama5d3_reg_layout = { 3198c2ecf20Sopenharmony_ci .timing_regs_offset = 0x600, 3208c2ecf20Sopenharmony_ci}; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic const struct atmel_hsmc_reg_layout sama5d2_reg_layout = { 3238c2ecf20Sopenharmony_ci .timing_regs_offset = 0x700, 3248c2ecf20Sopenharmony_ci}; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic const struct of_device_id atmel_smc_ids[] = { 3278c2ecf20Sopenharmony_ci { .compatible = "atmel,at91sam9260-smc", .data = NULL }, 3288c2ecf20Sopenharmony_ci { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout }, 3298c2ecf20Sopenharmony_ci { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout }, 3308c2ecf20Sopenharmony_ci { /* sentinel */ }, 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/** 3348c2ecf20Sopenharmony_ci * atmel_hsmc_get_reg_layout - retrieve the layout of HSMC registers 3358c2ecf20Sopenharmony_ci * @np: the HSMC regmap 3368c2ecf20Sopenharmony_ci * 3378c2ecf20Sopenharmony_ci * Retrieve the layout of HSMC registers. 3388c2ecf20Sopenharmony_ci * 3398c2ecf20Sopenharmony_ci * Returns NULL in case of SMC, a struct atmel_hsmc_reg_layout pointer 3408c2ecf20Sopenharmony_ci * in HSMC case, otherwise ERR_PTR(-EINVAL). 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ciconst struct atmel_hsmc_reg_layout * 3438c2ecf20Sopenharmony_ciatmel_hsmc_get_reg_layout(struct device_node *np) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci const struct of_device_id *match; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci match = of_match_node(atmel_smc_ids, np); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return match ? match->data : ERR_PTR(-EINVAL); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(atmel_hsmc_get_reg_layout); 352