diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 22:16:25 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 22:16:25 +0300 |
commit | d26f552ebbfb0f2c7fe712f457a038d60ed73daa (patch) | |
tree | 8d13c7344cabc99e738e0db7262b713708026fa0 /drivers/memory | |
parent | e897f267c51812bfecec45771a2d835c1a2bdacf (diff) | |
parent | ab6241ae07c3c698543b565e4ea41995a29a3f62 (diff) | |
download | linux-d26f552ebbfb0f2c7fe712f457a038d60ed73daa.tar.xz |
Merge tag 'mfd-next-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"New Drivers:
- Freescale MXS Low Resolution ADC
- Freescale i.MX23/i.MX28 LRADC touchscreen
- Motorola CPCAP Power Button
- TI LMU (Lighting Management Unit)
- Atmel SMC (Static Memory Controller)
New Device Support:
- Add support for X-Powers AXP803 to axp20x
- Add support for Dialog Semi DA9061 to da9062-core
- Add support for Intel Cougar Mountain to lpc_ich
- Add support for Intel Gemini Lake to lpc_ich
New Functionality:
- Add Device Tree support; wm831x-*, axp20x, ti-lmu, da9062, sun4i-gpadc
- Add IRQ sense support; motorola-cpcap
- Add ACPI support; cros_ec
- Add Reset support; altera-a10sr
- Add ADC support; axp20x
- Add AC Power support; axp20x
- Add Runtime PM support; atmel-ebi, exynos-lpass
- Add Battery Power Supply support; axp20x
- Add Clock support; exynos-lpass, hi655x-pmic
Fix-ups:
- Implicitly specify required headers; motorola-cpcap, intel_soc_pmic_bxtwc
- Add .remove() method; stm32-timers, exynos-lpass
- Remove unused code; intel_soc_pmic_core, intel-lpss-acpi, ipaq-micro, atmel-smc, menelaus
- Rename variables for clarity; axp20x
- Convert pr_warning() to pr_warn(); db8500-prcmu, sta2x11-mfd, twl4030-power
- Improve formatting; arizona-core, axp20x
- Use raw_spinlock_*() variants; asic3, t7l66xb, tc6393xb
- Simplify/refactor code; arizona-core, atmel-ebi
- Improve error checking; intel_soc_pmic_core
Bug Fixes:
- Ensure OMAP3630/3730 boards can successfully reboot; twl4030-power
- Correct max-register value; stm32-timers
- Extend timeout to account for clock stretching; cros_ec_spi
- Use correct IRQ trigger type; motorola-cpcap
- Fix bad use of IRQ sense register; motorola-cpcap
- Logic error "||" should be "&&"; mxs-lradc-ts"
* tag 'mfd-next-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (79 commits)
input: touchscreen: mxs-lradc: || vs && typos
dt-bindings: Add AXP803's regulator info
mfd: axp20x: Support AXP803 variant
dt-bindings: Add device tree binding for X-Powers AXP803 PMIC
dt-bindings: Make AXP20X compatible strings one per line
mfd: intel_soc_pmic_core: Fix unchecked return value
mfd: menelaus: Remove obsolete local_irq_disable() and local_irq_enable()
mfd: omap-usb-tll: Configure ULPIAUTOIDLE
mfd: omap-usb-tll: Fix inverted bit use for USB TLL mode
mfd: palmas: Fixed spelling mistake in error message
mfd: lpc_ich: Add support for Intel Gemini Lake SoC
mfd: hi655x: Add the clock cell to provide WiFi and Bluetooth
mfd: intel_soc_pmic: Fix a mess with compilation units
mfd: exynos-lpass: Add runtime PM support
mfd: exynos-lpass: Add missing remove() function
mfd: exynos-lpass: Add support for clocks
mfd: exynos-lpass: Remove pad retention control
iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
mfd: cpcap: Fix bad use of IRQ sense register
mfd: cpcap: Use ack_invert interrupts
...
Diffstat (limited to 'drivers/memory')
-rw-r--r-- | drivers/memory/Kconfig | 1 | ||||
-rw-r--r-- | drivers/memory/atmel-ebi.c | 584 |
2 files changed, 201 insertions, 384 deletions
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index ec80e35c8dfe..3ecc429297a0 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -30,6 +30,7 @@ config ATMEL_EBI default y depends on ARCH_AT91 && OF select MFD_SYSCON + select MFD_ATMEL_SMC help Driver for Atmel EBI controller. Used to configure the EBI (external bus interface) when the device- diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index 4e83a8b92665..35910f945bfa 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -18,219 +18,157 @@ #include <linux/of_device.h> #include <linux/regmap.h> -struct at91sam9_smc_timings { - u32 ncs_rd_setup_ns; - u32 nrd_setup_ns; - u32 ncs_wr_setup_ns; - u32 nwe_setup_ns; - u32 ncs_rd_pulse_ns; - u32 nrd_pulse_ns; - u32 ncs_wr_pulse_ns; - u32 nwe_pulse_ns; - u32 nrd_cycle_ns; - u32 nwe_cycle_ns; - u32 tdf_ns; -}; - -struct at91sam9_smc_generic_fields { - struct regmap_field *setup; - struct regmap_field *pulse; - struct regmap_field *cycle; - struct regmap_field *mode; -}; - -struct at91sam9_ebi_dev_config { - struct at91sam9_smc_timings timings; - u32 mode; -}; - -struct at91_ebi_dev_config { +struct atmel_ebi_dev_config { int cs; - union { - struct at91sam9_ebi_dev_config sam9; - }; + struct atmel_smc_cs_conf smcconf; }; -struct at91_ebi; +struct atmel_ebi; -struct at91_ebi_dev { +struct atmel_ebi_dev { struct list_head node; - struct at91_ebi *ebi; + struct atmel_ebi *ebi; u32 mode; int numcs; - struct at91_ebi_dev_config configs[]; + struct atmel_ebi_dev_config configs[]; }; -struct at91_ebi_caps { +struct atmel_ebi_caps { unsigned int available_cs; - const struct reg_field *ebi_csa; - void (*get_config)(struct at91_ebi_dev *ebid, - struct at91_ebi_dev_config *conf); - int (*xlate_config)(struct at91_ebi_dev *ebid, + unsigned int ebi_csa_offs; + void (*get_config)(struct atmel_ebi_dev *ebid, + struct atmel_ebi_dev_config *conf); + int (*xlate_config)(struct atmel_ebi_dev *ebid, struct device_node *configs_np, - struct at91_ebi_dev_config *conf); - int (*apply_config)(struct at91_ebi_dev *ebid, - struct at91_ebi_dev_config *conf); - int (*init)(struct at91_ebi *ebi); + struct atmel_ebi_dev_config *conf); + void (*apply_config)(struct atmel_ebi_dev *ebid, + struct atmel_ebi_dev_config *conf); }; -struct at91_ebi { +struct atmel_ebi { struct clk *clk; struct regmap *matrix; struct { struct regmap *regmap; struct clk *clk; } smc; - struct regmap_field *ebi_csa; struct device *dev; - const struct at91_ebi_caps *caps; + const struct atmel_ebi_caps *caps; struct list_head devs; - union { - struct at91sam9_smc_generic_fields sam9; - }; }; -static void at91sam9_ebi_get_config(struct at91_ebi_dev *ebid, - struct at91_ebi_dev_config *conf) -{ - struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9; - unsigned int clk_period = NSEC_PER_SEC / clk_get_rate(ebid->ebi->clk); - struct at91sam9_ebi_dev_config *config = &conf->sam9; - struct at91sam9_smc_timings *timings = &config->timings; - unsigned int val; - - regmap_fields_read(fields->mode, conf->cs, &val); - config->mode = val & ~AT91_SMC_TDF; - - val = (val & AT91_SMC_TDF) >> 16; - timings->tdf_ns = clk_period * val; - - regmap_fields_read(fields->setup, conf->cs, &val); - timings->ncs_rd_setup_ns = (val >> 24) & 0x1f; - timings->ncs_rd_setup_ns += ((val >> 29) & 0x1) * 128; - timings->ncs_rd_setup_ns *= clk_period; - timings->nrd_setup_ns = (val >> 16) & 0x1f; - timings->nrd_setup_ns += ((val >> 21) & 0x1) * 128; - timings->nrd_setup_ns *= clk_period; - timings->ncs_wr_setup_ns = (val >> 8) & 0x1f; - timings->ncs_wr_setup_ns += ((val >> 13) & 0x1) * 128; - timings->ncs_wr_setup_ns *= clk_period; - timings->nwe_setup_ns = val & 0x1f; - timings->nwe_setup_ns += ((val >> 5) & 0x1) * 128; - timings->nwe_setup_ns *= clk_period; - - regmap_fields_read(fields->pulse, conf->cs, &val); - timings->ncs_rd_pulse_ns = (val >> 24) & 0x3f; - timings->ncs_rd_pulse_ns += ((val >> 30) & 0x1) * 256; - timings->ncs_rd_pulse_ns *= clk_period; - timings->nrd_pulse_ns = (val >> 16) & 0x3f; - timings->nrd_pulse_ns += ((val >> 22) & 0x1) * 256; - timings->nrd_pulse_ns *= clk_period; - timings->ncs_wr_pulse_ns = (val >> 8) & 0x3f; - timings->ncs_wr_pulse_ns += ((val >> 14) & 0x1) * 256; - timings->ncs_wr_pulse_ns *= clk_period; - timings->nwe_pulse_ns = val & 0x3f; - timings->nwe_pulse_ns += ((val >> 6) & 0x1) * 256; - timings->nwe_pulse_ns *= clk_period; - - regmap_fields_read(fields->cycle, conf->cs, &val); - timings->nrd_cycle_ns = (val >> 16) & 0x7f; - timings->nrd_cycle_ns += ((val >> 23) & 0x3) * 256; - timings->nrd_cycle_ns *= clk_period; - timings->nwe_cycle_ns = val & 0x7f; - timings->nwe_cycle_ns += ((val >> 7) & 0x3) * 256; - timings->nwe_cycle_ns *= clk_period; -} +struct atmel_smc_timing_xlate { + const char *name; + int (*converter)(struct atmel_smc_cs_conf *conf, + unsigned int shift, unsigned int nycles); + unsigned int shift; +}; -static int at91_xlate_timing(struct device_node *np, const char *prop, - u32 *val, bool *required) -{ - if (!of_property_read_u32(np, prop, val)) { - *required = true; - return 0; - } +#define ATMEL_SMC_SETUP_XLATE(nm, pos) \ + { .name = nm, .converter = atmel_smc_cs_conf_set_setup, .shift = pos} - if (*required) - return -EINVAL; +#define ATMEL_SMC_PULSE_XLATE(nm, pos) \ + { .name = nm, .converter = atmel_smc_cs_conf_set_pulse, .shift = pos} - return 0; -} +#define ATMEL_SMC_CYCLE_XLATE(nm, pos) \ + { .name = nm, .converter = atmel_smc_cs_conf_set_setup, .shift = pos} -static int at91sam9_smc_xslate_timings(struct at91_ebi_dev *ebid, - struct device_node *np, - struct at91sam9_smc_timings *timings, - bool *required) +static void at91sam9_ebi_get_config(struct atmel_ebi_dev *ebid, + struct atmel_ebi_dev_config *conf) { - int ret; - - ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-setup-ns", - &timings->ncs_rd_setup_ns, required); - if (ret) - goto out; + atmel_smc_cs_conf_get(ebid->ebi->smc.regmap, conf->cs, + &conf->smcconf); +} - ret = at91_xlate_timing(np, "atmel,smc-nrd-setup-ns", - &timings->nrd_setup_ns, required); - if (ret) - goto out; +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); +} - ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-setup-ns", - &timings->ncs_wr_setup_ns, required); - if (ret) - goto out; +static const struct atmel_smc_timing_xlate timings_xlate_table[] = { + ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-rd-setup-ns", + ATMEL_SMC_NCS_RD_SHIFT), + ATMEL_SMC_SETUP_XLATE("atmel,smc-ncs-wr-setup-ns", + ATMEL_SMC_NCS_WR_SHIFT), + ATMEL_SMC_SETUP_XLATE("atmel,smc-nrd-setup-ns", ATMEL_SMC_NRD_SHIFT), + ATMEL_SMC_SETUP_XLATE("atmel,smc-nwe-setup-ns", ATMEL_SMC_NWE_SHIFT), + ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-rd-pulse-ns", + ATMEL_SMC_NCS_RD_SHIFT), + ATMEL_SMC_PULSE_XLATE("atmel,smc-ncs-wr-pulse-ns", + ATMEL_SMC_NCS_WR_SHIFT), + ATMEL_SMC_PULSE_XLATE("atmel,smc-nrd-pulse-ns", ATMEL_SMC_NRD_SHIFT), + ATMEL_SMC_PULSE_XLATE("atmel,smc-nwe-pulse-ns", ATMEL_SMC_NWE_SHIFT), + ATMEL_SMC_CYCLE_XLATE("atmel,smc-nrd-cycle-ns", ATMEL_SMC_NRD_SHIFT), + ATMEL_SMC_CYCLE_XLATE("atmel,smc-nwe-cycle-ns", ATMEL_SMC_NWE_SHIFT), +}; - ret = at91_xlate_timing(np, "atmel,smc-nwe-setup-ns", - &timings->nwe_setup_ns, required); - if (ret) - goto out; +static int atmel_ebi_xslate_smc_timings(struct atmel_ebi_dev *ebid, + struct device_node *np, + struct atmel_smc_cs_conf *smcconf) +{ + unsigned int clk_rate = clk_get_rate(ebid->ebi->clk); + unsigned int clk_period_ns = NSEC_PER_SEC / clk_rate; + bool required = false; + unsigned int ncycles; + int ret, i; + u32 val; - ret = at91_xlate_timing(np, "atmel,smc-ncs-rd-pulse-ns", - &timings->ncs_rd_pulse_ns, required); - if (ret) - goto out; + ret = of_property_read_u32(np, "atmel,smc-tdf-ns", &val); + if (!ret) { + required = true; + ncycles = DIV_ROUND_UP(val, clk_period_ns); + if (ncycles > ATMEL_SMC_MODE_TDF_MAX || + ncycles < ATMEL_SMC_MODE_TDF_MIN) { + ret = -EINVAL; + goto out; + } - ret = at91_xlate_timing(np, "atmel,smc-nrd-pulse-ns", - &timings->nrd_pulse_ns, required); - if (ret) - goto out; + smcconf->mode |= ATMEL_SMC_MODE_TDF(ncycles); + } - ret = at91_xlate_timing(np, "atmel,smc-ncs-wr-pulse-ns", - &timings->ncs_wr_pulse_ns, required); - if (ret) - goto out; + for (i = 0; i < ARRAY_SIZE(timings_xlate_table); i++) { + const struct atmel_smc_timing_xlate *xlate; - ret = at91_xlate_timing(np, "atmel,smc-nwe-pulse-ns", - &timings->nwe_pulse_ns, required); - if (ret) - goto out; + xlate = &timings_xlate_table[i]; - ret = at91_xlate_timing(np, "atmel,smc-nwe-cycle-ns", - &timings->nwe_cycle_ns, required); - if (ret) - goto out; + ret = of_property_read_u32(np, xlate->name, &val); + if (ret) { + if (!required) + continue; + else + break; + } - ret = at91_xlate_timing(np, "atmel,smc-nrd-cycle-ns", - &timings->nrd_cycle_ns, required); - if (ret) - goto out; + if (!required) { + ret = -EINVAL; + break; + } - ret = at91_xlate_timing(np, "atmel,smc-tdf-ns", - &timings->tdf_ns, required); + ncycles = DIV_ROUND_UP(val, clk_period_ns); + ret = xlate->converter(smcconf, xlate->shift, ncycles); + if (ret) + goto out; + } out: - if (ret) + if (ret) { dev_err(ebid->ebi->dev, "missing or invalid timings definition in %s", np->full_name); + return ret; + } - return ret; + return required; } -static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid, - struct device_node *np, - struct at91_ebi_dev_config *conf) +static int atmel_ebi_xslate_smc_config(struct atmel_ebi_dev *ebid, + struct device_node *np, + struct atmel_ebi_dev_config *conf) { - struct at91sam9_ebi_dev_config *config = &conf->sam9; + struct atmel_smc_cs_conf *smcconf = &conf->smcconf; bool required = false; const char *tmp_str; u32 tmp; @@ -240,15 +178,15 @@ static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid, if (!ret) { switch (tmp) { case 8: - config->mode |= AT91_SMC_DBW_8; + smcconf->mode |= ATMEL_SMC_MODE_DBW_8; break; case 16: - config->mode |= AT91_SMC_DBW_16; + smcconf->mode |= ATMEL_SMC_MODE_DBW_16; break; case 32: - config->mode |= AT91_SMC_DBW_32; + smcconf->mode |= ATMEL_SMC_MODE_DBW_32; break; default: @@ -259,28 +197,28 @@ static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid, } if (of_property_read_bool(np, "atmel,smc-tdf-optimized")) { - config->mode |= AT91_SMC_TDFMODE_OPTIMIZED; + smcconf->mode |= ATMEL_SMC_MODE_TDFMODE_OPTIMIZED; required = true; } tmp_str = NULL; of_property_read_string(np, "atmel,smc-byte-access-type", &tmp_str); if (tmp_str && !strcmp(tmp_str, "write")) { - config->mode |= AT91_SMC_BAT_WRITE; + smcconf->mode |= ATMEL_SMC_MODE_BAT_WRITE; required = true; } tmp_str = NULL; of_property_read_string(np, "atmel,smc-read-mode", &tmp_str); if (tmp_str && !strcmp(tmp_str, "nrd")) { - config->mode |= AT91_SMC_READMODE_NRD; + smcconf->mode |= ATMEL_SMC_MODE_READMODE_NRD; required = true; } tmp_str = NULL; of_property_read_string(np, "atmel,smc-write-mode", &tmp_str); if (tmp_str && !strcmp(tmp_str, "nwe")) { - config->mode |= AT91_SMC_WRITEMODE_NWE; + smcconf->mode |= ATMEL_SMC_MODE_WRITEMODE_NWE; required = true; } @@ -288,9 +226,9 @@ static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid, of_property_read_string(np, "atmel,smc-exnw-mode", &tmp_str); if (tmp_str) { if (!strcmp(tmp_str, "frozen")) - config->mode |= AT91_SMC_EXNWMODE_FROZEN; + smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_FROZEN; else if (!strcmp(tmp_str, "ready")) - config->mode |= AT91_SMC_EXNWMODE_READY; + smcconf->mode |= ATMEL_SMC_MODE_EXNWMODE_READY; else if (strcmp(tmp_str, "disabled")) return -EINVAL; @@ -301,164 +239,63 @@ static int at91sam9_ebi_xslate_config(struct at91_ebi_dev *ebid, if (!ret) { switch (tmp) { case 4: - config->mode |= AT91_SMC_PS_4; + smcconf->mode |= ATMEL_SMC_MODE_PS_4; break; case 8: - config->mode |= AT91_SMC_PS_8; + smcconf->mode |= ATMEL_SMC_MODE_PS_8; break; case 16: - config->mode |= AT91_SMC_PS_16; + smcconf->mode |= ATMEL_SMC_MODE_PS_16; break; case 32: - config->mode |= AT91_SMC_PS_32; + smcconf->mode |= ATMEL_SMC_MODE_PS_32; break; default: return -EINVAL; } - config->mode |= AT91_SMC_PMEN; + smcconf->mode |= ATMEL_SMC_MODE_PMEN; required = true; } - ret = at91sam9_smc_xslate_timings(ebid, np, &config->timings, - &required); + ret = atmel_ebi_xslate_smc_timings(ebid, np, &conf->smcconf); if (ret) - return ret; - - return required; -} - -static int at91sam9_ebi_apply_config(struct at91_ebi_dev *ebid, - struct at91_ebi_dev_config *conf) -{ - unsigned int clk_rate = clk_get_rate(ebid->ebi->clk); - unsigned int clk_period = NSEC_PER_SEC / clk_rate; - struct at91sam9_ebi_dev_config *config = &conf->sam9; - struct at91sam9_smc_timings *timings = &config->timings; - struct at91sam9_smc_generic_fields *fields = &ebid->ebi->sam9; - u32 coded_val; - u32 val; + return -EINVAL; - coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate, - timings->ncs_rd_setup_ns); - val = AT91SAM9_SMC_NCS_NRDSETUP(coded_val); - coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate, - timings->nrd_setup_ns); - val |= AT91SAM9_SMC_NRDSETUP(coded_val); - coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate, - timings->ncs_wr_setup_ns); - val |= AT91SAM9_SMC_NCS_WRSETUP(coded_val); - coded_val = at91sam9_smc_setup_ns_to_cycles(clk_rate, - timings->nwe_setup_ns); - val |= AT91SAM9_SMC_NWESETUP(coded_val); - regmap_fields_write(fields->setup, conf->cs, val); - - coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate, - timings->ncs_rd_pulse_ns); - val = AT91SAM9_SMC_NCS_NRDPULSE(coded_val); - coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate, - timings->nrd_pulse_ns); - val |= AT91SAM9_SMC_NRDPULSE(coded_val); - coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate, - timings->ncs_wr_pulse_ns); - val |= AT91SAM9_SMC_NCS_WRPULSE(coded_val); - coded_val = at91sam9_smc_pulse_ns_to_cycles(clk_rate, - timings->nwe_pulse_ns); - val |= AT91SAM9_SMC_NWEPULSE(coded_val); - regmap_fields_write(fields->pulse, conf->cs, val); - - coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate, - timings->nrd_cycle_ns); - val = AT91SAM9_SMC_NRDCYCLE(coded_val); - coded_val = at91sam9_smc_cycle_ns_to_cycles(clk_rate, - timings->nwe_cycle_ns); - val |= AT91SAM9_SMC_NWECYCLE(coded_val); - regmap_fields_write(fields->cycle, conf->cs, val); - - val = DIV_ROUND_UP(timings->tdf_ns, clk_period); - if (val > AT91_SMC_TDF_MAX) - val = AT91_SMC_TDF_MAX; - regmap_fields_write(fields->mode, conf->cs, - config->mode | AT91_SMC_TDF_(val)); + if ((ret > 0 && !required) || (!ret && required)) { + dev_err(ebid->ebi->dev, "missing atmel,smc- properties in %s", + np->full_name); + return -EINVAL; + } - return 0; + return required; } -static int at91sam9_ebi_init(struct at91_ebi *ebi) +static void at91sam9_ebi_apply_config(struct atmel_ebi_dev *ebid, + struct atmel_ebi_dev_config *conf) { - struct at91sam9_smc_generic_fields *fields = &ebi->sam9; - struct reg_field field = REG_FIELD(0, 0, 31); - - field.id_size = fls(ebi->caps->available_cs); - field.id_offset = AT91SAM9_SMC_GENERIC_BLK_SZ; - - field.reg = AT91SAM9_SMC_SETUP(AT91SAM9_SMC_GENERIC); - fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap, - field); - if (IS_ERR(fields->setup)) - return PTR_ERR(fields->setup); - - field.reg = AT91SAM9_SMC_PULSE(AT91SAM9_SMC_GENERIC); - fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap, - field); - if (IS_ERR(fields->pulse)) - return PTR_ERR(fields->pulse); - - field.reg = AT91SAM9_SMC_CYCLE(AT91SAM9_SMC_GENERIC); - fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap, - field); - if (IS_ERR(fields->cycle)) - return PTR_ERR(fields->cycle); - - field.reg = AT91SAM9_SMC_MODE(AT91SAM9_SMC_GENERIC); - fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap, - field); - return PTR_ERR_OR_ZERO(fields->mode); + atmel_smc_cs_conf_apply(ebid->ebi->smc.regmap, conf->cs, + &conf->smcconf); } -static int sama5d3_ebi_init(struct at91_ebi *ebi) +static void sama5_ebi_apply_config(struct atmel_ebi_dev *ebid, + struct atmel_ebi_dev_config *conf) { - struct at91sam9_smc_generic_fields *fields = &ebi->sam9; - struct reg_field field = REG_FIELD(0, 0, 31); - - field.id_size = fls(ebi->caps->available_cs); - field.id_offset = SAMA5_SMC_GENERIC_BLK_SZ; - - field.reg = AT91SAM9_SMC_SETUP(SAMA5_SMC_GENERIC); - fields->setup = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap, - field); - if (IS_ERR(fields->setup)) - return PTR_ERR(fields->setup); - - field.reg = AT91SAM9_SMC_PULSE(SAMA5_SMC_GENERIC); - fields->pulse = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap, - field); - if (IS_ERR(fields->pulse)) - return PTR_ERR(fields->pulse); - - field.reg = AT91SAM9_SMC_CYCLE(SAMA5_SMC_GENERIC); - fields->cycle = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap, - field); - if (IS_ERR(fields->cycle)) - return PTR_ERR(fields->cycle); - - field.reg = SAMA5_SMC_MODE(SAMA5_SMC_GENERIC); - fields->mode = devm_regmap_field_alloc(ebi->dev, ebi->smc.regmap, - field); - return PTR_ERR_OR_ZERO(fields->mode); + atmel_hsmc_cs_conf_apply(ebid->ebi->smc.regmap, conf->cs, + &conf->smcconf); } -static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np, - int reg_cells) +static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np, + int reg_cells) { - const struct at91_ebi_caps *caps = ebi->caps; - struct at91_ebi_dev_config conf = { }; + const struct atmel_ebi_caps *caps = ebi->caps; + struct atmel_ebi_dev_config conf = { }; struct device *dev = ebi->dev; - struct at91_ebi_dev *ebid; + struct atmel_ebi_dev *ebid; unsigned long cslines = 0; int ret, numcs = 0, nentries, i; bool apply = false; @@ -495,6 +332,7 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np, return -ENOMEM; ebid->ebi = ebi; + ebid->numcs = numcs; ret = caps->xlate_config(ebid, np, &conf); if (ret < 0) @@ -508,9 +346,7 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np, if (apply) { conf.cs = cs; - ret = caps->apply_config(ebid, &conf); - if (ret) - return ret; + caps->apply_config(ebid, &conf); } caps->get_config(ebid, &ebid->configs[i]); @@ -519,9 +355,10 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np, * Attach the EBI device to the generic SMC logic if at least * one "atmel,smc-" property is present. */ - if (ebi->ebi_csa && apply) - regmap_field_update_bits(ebi->ebi_csa, - BIT(cs), 0); + if (ebi->caps->ebi_csa_offs && apply) + regmap_update_bits(ebi->matrix, + ebi->caps->ebi_csa_offs, + BIT(cs), 0); i++; } @@ -531,102 +368,70 @@ static int at91_ebi_dev_setup(struct at91_ebi *ebi, struct device_node *np, return 0; } -static const struct reg_field at91sam9260_ebi_csa = - REG_FIELD(AT91SAM9260_MATRIX_EBICSA, 0, - AT91_MATRIX_EBI_NUM_CS - 1); - -static const struct at91_ebi_caps at91sam9260_ebi_caps = { +static const struct atmel_ebi_caps at91sam9260_ebi_caps = { .available_cs = 0xff, - .ebi_csa = &at91sam9260_ebi_csa, + .ebi_csa_offs = AT91SAM9260_MATRIX_EBICSA, .get_config = at91sam9_ebi_get_config, - .xlate_config = at91sam9_ebi_xslate_config, + .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, - .init = at91sam9_ebi_init, }; -static const struct reg_field at91sam9261_ebi_csa = - REG_FIELD(AT91SAM9261_MATRIX_EBICSA, 0, - AT91_MATRIX_EBI_NUM_CS - 1); - -static const struct at91_ebi_caps at91sam9261_ebi_caps = { +static const struct atmel_ebi_caps at91sam9261_ebi_caps = { .available_cs = 0xff, - .ebi_csa = &at91sam9261_ebi_csa, + .ebi_csa_offs = AT91SAM9261_MATRIX_EBICSA, .get_config = at91sam9_ebi_get_config, - .xlate_config = at91sam9_ebi_xslate_config, + .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, - .init = at91sam9_ebi_init, }; -static const struct reg_field at91sam9263_ebi0_csa = - REG_FIELD(AT91SAM9263_MATRIX_EBI0CSA, 0, - AT91_MATRIX_EBI_NUM_CS - 1); - -static const struct at91_ebi_caps at91sam9263_ebi0_caps = { +static const struct atmel_ebi_caps at91sam9263_ebi0_caps = { .available_cs = 0x3f, - .ebi_csa = &at91sam9263_ebi0_csa, + .ebi_csa_offs = AT91SAM9263_MATRIX_EBI0CSA, .get_config = at91sam9_ebi_get_config, - .xlate_config = at91sam9_ebi_xslate_config, + .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, - .init = at91sam9_ebi_init, }; -static const struct reg_field at91sam9263_ebi1_csa = - REG_FIELD(AT91SAM9263_MATRIX_EBI1CSA, 0, - AT91_MATRIX_EBI_NUM_CS - 1); - -static const struct at91_ebi_caps at91sam9263_ebi1_caps = { +static const struct atmel_ebi_caps at91sam9263_ebi1_caps = { .available_cs = 0x7, - .ebi_csa = &at91sam9263_ebi1_csa, + .ebi_csa_offs = AT91SAM9263_MATRIX_EBI1CSA, .get_config = at91sam9_ebi_get_config, - .xlate_config = at91sam9_ebi_xslate_config, + .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, - .init = at91sam9_ebi_init, }; -static const struct reg_field at91sam9rl_ebi_csa = - REG_FIELD(AT91SAM9RL_MATRIX_EBICSA, 0, - AT91_MATRIX_EBI_NUM_CS - 1); - -static const struct at91_ebi_caps at91sam9rl_ebi_caps = { +static const struct atmel_ebi_caps at91sam9rl_ebi_caps = { .available_cs = 0x3f, - .ebi_csa = &at91sam9rl_ebi_csa, + .ebi_csa_offs = AT91SAM9RL_MATRIX_EBICSA, .get_config = at91sam9_ebi_get_config, - .xlate_config = at91sam9_ebi_xslate_config, + .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, - .init = at91sam9_ebi_init, }; -static const struct reg_field at91sam9g45_ebi_csa = - REG_FIELD(AT91SAM9G45_MATRIX_EBICSA, 0, - AT91_MATRIX_EBI_NUM_CS - 1); - -static const struct at91_ebi_caps at91sam9g45_ebi_caps = { +static const struct atmel_ebi_caps at91sam9g45_ebi_caps = { .available_cs = 0x3f, - .ebi_csa = &at91sam9g45_ebi_csa, + .ebi_csa_offs = AT91SAM9G45_MATRIX_EBICSA, .get_config = at91sam9_ebi_get_config, - .xlate_config = at91sam9_ebi_xslate_config, + .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, - .init = at91sam9_ebi_init, }; -static const struct at91_ebi_caps at91sam9x5_ebi_caps = { +static const struct atmel_ebi_caps at91sam9x5_ebi_caps = { .available_cs = 0x3f, - .ebi_csa = &at91sam9263_ebi0_csa, + .ebi_csa_offs = AT91SAM9X5_MATRIX_EBICSA, .get_config = at91sam9_ebi_get_config, - .xlate_config = at91sam9_ebi_xslate_config, + .xlate_config = atmel_ebi_xslate_smc_config, .apply_config = at91sam9_ebi_apply_config, - .init = at91sam9_ebi_init, }; -static const struct at91_ebi_caps sama5d3_ebi_caps = { +static const struct atmel_ebi_caps sama5d3_ebi_caps = { .available_cs = 0xf, - .get_config = at91sam9_ebi_get_config, - .xlate_config = at91sam9_ebi_xslate_config, - .apply_config = at91sam9_ebi_apply_config, - .init = sama5d3_ebi_init, + .get_config = sama5_ebi_get_config, + .xlate_config = atmel_ebi_xslate_smc_config, + .apply_config = sama5_ebi_apply_config, }; -static const struct of_device_id at91_ebi_id_table[] = { +static const struct of_device_id atmel_ebi_id_table[] = { { .compatible = "atmel,at91sam9260-ebi", .data = &at91sam9260_ebi_caps, @@ -662,7 +467,7 @@ static const struct of_device_id at91_ebi_id_table[] = { { /* sentinel */ } }; -static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np) +static int atmel_ebi_dev_disable(struct atmel_ebi *ebi, struct device_node *np) { struct device *dev = ebi->dev; struct property *newprop; @@ -684,17 +489,17 @@ static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np) return of_update_property(np, newprop); } -static int at91_ebi_probe(struct platform_device *pdev) +static int atmel_ebi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *child, *np = dev->of_node, *smc_np; const struct of_device_id *match; - struct at91_ebi *ebi; + struct atmel_ebi *ebi; int ret, reg_cells; struct clk *clk; u32 val; - match = of_match_device(at91_ebi_id_table, dev); + match = of_match_device(atmel_ebi_id_table, dev); if (!match || !match->data) return -EINVAL; @@ -702,6 +507,8 @@ static int at91_ebi_probe(struct platform_device *pdev) if (!ebi) return -ENOMEM; + platform_set_drvdata(pdev, ebi); + INIT_LIST_HEAD(&ebi->devs); ebi->caps = match->data; ebi->dev = dev; @@ -733,22 +540,13 @@ static int at91_ebi_probe(struct platform_device *pdev) * The sama5d3 does not provide an EBICSA register and thus does need * to access the matrix registers. */ - if (ebi->caps->ebi_csa) { + if (ebi->caps->ebi_csa_offs) { ebi->matrix = syscon_regmap_lookup_by_phandle(np, "atmel,matrix"); if (IS_ERR(ebi->matrix)) return PTR_ERR(ebi->matrix); - - ebi->ebi_csa = regmap_field_alloc(ebi->matrix, - *ebi->caps->ebi_csa); - if (IS_ERR(ebi->ebi_csa)) - return PTR_ERR(ebi->ebi_csa); } - ret = ebi->caps->init(ebi); - if (ret) - return ret; - ret = of_property_read_u32(np, "#address-cells", &val); if (ret) { dev_err(dev, "missing #address-cells property\n"); @@ -769,12 +567,12 @@ static int at91_ebi_probe(struct platform_device *pdev) if (!of_find_property(child, "reg", NULL)) continue; - ret = at91_ebi_dev_setup(ebi, child, reg_cells); + ret = atmel_ebi_dev_setup(ebi, child, reg_cells); if (ret) { dev_err(dev, "failed to configure EBI bus for %s, disabling the device", child->full_name); - ret = at91_ebi_dev_disable(ebi, child); + ret = atmel_ebi_dev_disable(ebi, child); if (ret) return ret; } @@ -783,10 +581,28 @@ static int at91_ebi_probe(struct platform_device *pdev) return of_platform_populate(np, NULL, NULL, dev); } -static struct platform_driver at91_ebi_driver = { +static int atmel_ebi_resume(struct device *dev) +{ + struct atmel_ebi *ebi = dev_get_drvdata(dev); + struct atmel_ebi_dev *ebid; + + list_for_each_entry(ebid, &ebi->devs, node) { + int i; + + for (i = 0; i < ebid->numcs; i++) + ebid->ebi->caps->apply_config(ebid, &ebid->configs[i]); + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(atmel_ebi_pm_ops, NULL, atmel_ebi_resume); + +static struct platform_driver atmel_ebi_driver = { .driver = { .name = "atmel-ebi", - .of_match_table = at91_ebi_id_table, + .of_match_table = atmel_ebi_id_table, + .pm = &atmel_ebi_pm_ops, }, }; -builtin_platform_driver_probe(at91_ebi_driver, at91_ebi_probe); +builtin_platform_driver_probe(atmel_ebi_driver, atmel_ebi_probe); |