diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-05-29 19:54:21 -0700 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-05-29 19:54:21 -0700 |
| commit | d8f797c60661a90ee26ca9330cf85ede9aa2ec17 (patch) | |
| tree | 5038609885fc3e4cb7f329d974875ac4411c6af5 /drivers/mfd | |
| parent | 8fd708157a592a376c4d0b3b2ba23b9e9f79caa5 (diff) | |
| parent | 5ed02dbb497422bf225783f46e6eadd237d23d6b (diff) | |
| download | linux-d8f797c60661a90ee26ca9330cf85ede9aa2ec17.tar.gz linux-d8f797c60661a90ee26ca9330cf85ede9aa2ec17.tar.bz2 linux-d8f797c60661a90ee26ca9330cf85ede9aa2ec17.zip | |
Merge tag 'v4.12-rc3' into next
Sync with mainline to bring in changes in platform drovers dropping
calls to sparse_keymap_free() so that we can remove it for good.
Diffstat (limited to 'drivers/mfd')
39 files changed, 1826 insertions, 229 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 55ecdfb74d31..3eb5c93595f6 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -121,6 +121,10 @@ config MFD_ATMEL_HLCDC additional drivers must be enabled in order to use the functionality of the device. +config MFD_ATMEL_SMC + bool + select MFD_SYSCON + config MFD_BCM590XX tristate "Broadcom BCM590xx PMUs" select MFD_CORE @@ -263,13 +267,14 @@ config MFD_DA9055 called "da9055" config MFD_DA9062 - tristate "Dialog Semiconductor DA9062 PMIC Support" + tristate "Dialog Semiconductor DA9062/61 PMIC Support" select MFD_CORE select REGMAP_I2C select REGMAP_IRQ depends on I2C help - Say yes here for support for the Dialog Semiconductor DA9062 PMIC. + Say yes here for support for the Dialog Semiconductor DA9061 and + DA9062 PMICs. This includes the I2C driver and core APIs. Additional drivers must be enabled in order to use the functionality of the device. @@ -344,6 +349,23 @@ config MFD_MC13XXX_I2C help Select this if your MC13xxx is connected via an I2C bus. +config MFD_MXS_LRADC + tristate "Freescale i.MX23/i.MX28 LRADC" + depends on ARCH_MXS || COMPILE_TEST + select MFD_CORE + select STMP_DEVICE + help + Say yes here to build support for the Low Resolution + Analog-to-Digital Converter (LRADC) found on the i.MX23 and i.MX28 + processors. This driver provides common support for accessing the + device, additional drivers must be enabled in order to use the + functionality of the device: + mxs-lradc-adc for ADC readings + mxs-lradc-ts for touchscreen support + + This driver can also be built as a module. If so, the module will be + called mxs-lradc. + config MFD_MX25_TSADC tristate "Freescale i.MX25 integrated Touchscreen and ADC unit" select REGMAP_MMIO @@ -425,18 +447,29 @@ config LPC_SCH System Management Bus and General Purpose I/O. config INTEL_SOC_PMIC - bool "Support for Intel Atom SoC PMIC" + bool "Support for Crystal Cove PMIC" depends on GPIOLIB depends on I2C=y select MFD_CORE select REGMAP_I2C select REGMAP_IRQ help - Select this option to enable support for the PMIC device + Select this option to enable support for Crystal Cove PMIC on some Intel SoC systems. The PMIC provides ADC, GPIO, thermal, charger and related power management functions on these systems. +config INTEL_SOC_PMIC_BXTWC + tristate "Support for Intel Broxton Whiskey Cove PMIC" + depends on INTEL_PMC_IPC + select MFD_CORE + select REGMAP_IRQ + help + Select this option to enable support for Whiskey Cove PMIC + on Intel Broxton systems. The PMIC provides ADC, GPIO, + thermal, charger and related power management functions + on these systems. + config MFD_INTEL_LPSS tristate select COMMON_CLK @@ -1164,6 +1197,18 @@ config MFD_LP8788 TI LP8788 PMU supports regulators, battery charger, RTC, ADC, backlight driver and current sinks. +config MFD_TI_LMU + tristate "TI Lighting Management Unit driver" + depends on I2C + select MFD_CORE + select REGMAP_I2C + help + Say yes here to enable support for TI LMU chips. + + TI LMU MFD supports LM3532, LM3631, LM3632, LM3633, LM3695 and LM3697. + It consists of backlight, LED and regulator driver. + It provides consistent device controls for lighting functions. + config MFD_OMAP_USB_HOST bool "TI OMAP USBHS core and TLL driver" depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 31ce07611a6f..c16bf1ea0ea9 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -10,7 +10,9 @@ obj-$(CONFIG_MFD_ACT8945A) += act8945a.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o -obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o +cros_ec_core-objs := cros_ec.o +cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o +obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o @@ -125,6 +127,8 @@ obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o obj-$(CONFIG_MFD_LP3943) += lp3943.o obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o +obj-$(CONFIG_MFD_TI_LMU) += ti-lmu.o + da9055-objs := da9055-core.o da9055-i2c.o obj-$(CONFIG_MFD_DA9055) += da9055.o obj-$(CONFIG_MFD_DA9062) += da9062-core.o @@ -181,6 +185,7 @@ obj-$(CONFIG_MFD_TPS65090) += tps65090.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o +obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o @@ -207,11 +212,12 @@ obj-$(CONFIG_MFD_RT5033) += rt5033.o obj-$(CONFIG_MFD_SKY81452) += sky81452.o intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o -intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o +obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_MFD_MT6397) += mt6397-core.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o +obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o diff --git a/drivers/mfd/altera-a10sr.c b/drivers/mfd/altera-a10sr.c index 06e1f7fc5605..96e7d2cb7b89 100644 --- a/drivers/mfd/altera-a10sr.c +++ b/drivers/mfd/altera-a10sr.c @@ -33,6 +33,10 @@ static const struct mfd_cell altr_a10sr_subdev_info[] = { .name = "altr_a10sr_gpio", .of_compatible = "altr,a10sr-gpio", }, + { + .name = "altr_a10sr_reset", + .of_compatible = "altr,a10sr-reset", + }, }; static bool altr_a10sr_reg_readable(struct device *dev, unsigned int reg) diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index b6d4bc63c426..75488e65cd96 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -235,29 +235,25 @@ static irqreturn_t arizona_overclocked(int irq, void *data) return IRQ_HANDLED; } +#define ARIZONA_REG_POLL_DELAY_US 7500 + static int arizona_poll_reg(struct arizona *arizona, - int timeout, unsigned int reg, + int timeout_ms, unsigned int reg, unsigned int mask, unsigned int target) { unsigned int val = 0; - int ret, i; - - for (i = 0; i < timeout; i++) { - ret = regmap_read(arizona->regmap, reg, &val); - if (ret != 0) { - dev_err(arizona->dev, "Failed to read reg %u: %d\n", - reg, ret); - continue; - } - - if ((val & mask) == target) - return 0; + int ret; - usleep_range(1000, 5000); - } + ret = regmap_read_poll_timeout(arizona->regmap, + ARIZONA_INTERRUPT_RAW_STATUS_5, val, + ((val & mask) == target), + ARIZONA_REG_POLL_DELAY_US, + timeout_ms * 1000); + if (ret) + dev_err(arizona->dev, "Polling reg 0x%x timed out: %x\n", + reg, val); - dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); - return -ETIMEDOUT; + return ret; } static int arizona_wait_for_boot(struct arizona *arizona) @@ -269,7 +265,7 @@ static int arizona_wait_for_boot(struct arizona *arizona) * we won't race with the interrupt handler as it'll be blocked on * runtime resume. */ - ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, + ret = arizona_poll_reg(arizona, 30, ARIZONA_INTERRUPT_RAW_STATUS_5, ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); if (!ret) @@ -339,13 +335,11 @@ static int arizona_enable_freerun_sysclk(struct arizona *arizona, ret); return ret; } - ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, + ret = arizona_poll_reg(arizona, 180, ARIZONA_INTERRUPT_RAW_STATUS_5, ARIZONA_FLL1_CLOCK_OK_STS, ARIZONA_FLL1_CLOCK_OK_STS); - if (ret) { - ret = -ETIMEDOUT; + if (ret) goto err_fll; - } ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); if (ret) { @@ -405,13 +399,11 @@ static int wm5102_apply_hardware_patch(struct arizona *arizona) goto err; } - ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, + ret = arizona_poll_reg(arizona, 30, ARIZONA_WRITE_SEQUENCER_CTRL_1, ARIZONA_WSEQ_BUSY, 0); - if (ret) { + if (ret) regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, ARIZONA_WSEQ_ABORT); - ret = -ETIMEDOUT; - } err: err = arizona_disable_freerun_sysclk(arizona, &state); diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 0413c8159551..cf2e25ab2940 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -78,7 +78,7 @@ struct asic3 { unsigned int bus_shift; unsigned int irq_nr; unsigned int irq_base; - spinlock_t lock; + raw_spinlock_t lock; u16 irq_bothedge[4]; struct gpio_chip gpio; struct device *dev; @@ -108,14 +108,14 @@ static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) unsigned long flags; u32 val; - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); val = asic3_read_register(asic, reg); if (set) val |= bits; else val &= ~bits; asic3_write_register(asic, reg, val); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); } /* IRQs */ @@ -129,13 +129,13 @@ static void asic3_irq_flip_edge(struct asic3 *asic, u16 edge; unsigned long flags; - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); edge = asic3_read_register(asic, base + ASIC3_GPIO_EDGE_TRIGGER); edge ^= bit; asic3_write_register(asic, base + ASIC3_GPIO_EDGE_TRIGGER, edge); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); } static void asic3_irq_demux(struct irq_desc *desc) @@ -151,10 +151,10 @@ static void asic3_irq_demux(struct irq_desc *desc) u32 status; int bank; - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); status = asic3_read_register(asic, ASIC3_OFFSET(INTR, P_INT_STAT)); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); /* Check all ten register bits */ if ((status & 0x3ff) == 0) @@ -167,7 +167,7 @@ static void asic3_irq_demux(struct irq_desc *desc) base = ASIC3_GPIO_A_BASE + bank * ASIC3_GPIO_BASE_INCR; - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); istat = asic3_read_register(asic, base + ASIC3_GPIO_INT_STATUS); @@ -175,7 +175,7 @@ static void asic3_irq_demux(struct irq_desc *desc) asic3_write_register(asic, base + ASIC3_GPIO_INT_STATUS, 0); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); for (i = 0; i < ASIC3_GPIOS_PER_BANK; i++) { int bit = (1 << i); @@ -230,11 +230,11 @@ static void asic3_mask_gpio_irq(struct irq_data *data) bank = asic3_irq_to_bank(asic, data->irq); index = asic3_irq_to_index(asic, data->irq); - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); val |= 1 << index; asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); } static void asic3_mask_irq(struct irq_data *data) @@ -243,7 +243,7 @@ static void asic3_mask_irq(struct irq_data *data) int regval; unsigned long flags; - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); regval = asic3_read_register(asic, ASIC3_INTR_BASE + ASIC3_INTR_INT_MASK); @@ -255,7 +255,7 @@ static void asic3_mask_irq(struct irq_data *data) ASIC3_INTR_BASE + ASIC3_INTR_INT_MASK, regval); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); } static void asic3_unmask_gpio_irq(struct irq_data *data) @@ -267,11 +267,11 @@ static void asic3_unmask_gpio_irq(struct irq_data *data) bank = asic3_irq_to_bank(asic, data->irq); index = asic3_irq_to_index(asic, data->irq); - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); val = asic3_read_register(asic, bank + ASIC3_GPIO_MASK); val &= ~(1 << index); asic3_write_register(asic, bank + ASIC3_GPIO_MASK, val); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); } static void asic3_unmask_irq(struct irq_data *data) @@ -280,7 +280,7 @@ static void asic3_unmask_irq(struct irq_data *data) int regval; unsigned long flags; - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); regval = asic3_read_register(asic, ASIC3_INTR_BASE + ASIC3_INTR_INT_MASK); @@ -292,7 +292,7 @@ static void asic3_unmask_irq(struct irq_data *data) ASIC3_INTR_BASE + ASIC3_INTR_INT_MASK, regval); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); } static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type) @@ -306,7 +306,7 @@ static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type) index = asic3_irq_to_index(asic, data->irq); bit = 1<<index; - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); level = asic3_read_register(asic, bank + ASIC3_GPIO_LEVEL_TRIGGER); edge = asic3_read_register(asic, @@ -348,7 +348,7 @@ static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type) edge); asic3_write_register(asic, bank + ASIC3_GPIO_TRIGGER_TYPE, trigger); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); return 0; } @@ -455,7 +455,7 @@ static int asic3_gpio_direction(struct gpio_chip *chip, return -EINVAL; } - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_DIRECTION); @@ -467,7 +467,7 @@ static int asic3_gpio_direction(struct gpio_chip *chip, asic3_write_register(asic, gpio_base + ASIC3_GPIO_DIRECTION, out_reg); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); return 0; @@ -524,7 +524,7 @@ static void asic3_gpio_set(struct gpio_chip *chip, mask = ASIC3_GPIO_TO_MASK(offset); - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); out_reg = asic3_read_register(asic, gpio_base + ASIC3_GPIO_OUT); @@ -535,7 +535,7 @@ static void asic3_gpio_set(struct gpio_chip *chip, asic3_write_register(asic, gpio_base + ASIC3_GPIO_OUT, out_reg); - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); } static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset) @@ -611,13 +611,13 @@ static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk) unsigned long flags; u32 cdex; - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); if (clk->enabled++ == 0) { cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); cdex |= clk->cdex; asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); } - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); } static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk) @@ -627,13 +627,13 @@ static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk) WARN_ON(clk->enabled == 0); - spin_lock_irqsave(&asic->lock, flags); + raw_spin_lock_irqsave(&asic->lock, flags); if (--clk->enabled == 0) { cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX)); cdex &= ~clk->cdex; asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex); } - spin_unlock_irqrestore(&asic->lock, flags); + raw_spin_unlock_irqrestore(&asic->lock, flags); } /* MFD cells (SPI, PWM, LED, DS1WM, MMC) */ @@ -963,7 +963,7 @@ static int __init asic3_probe(struct platform_device *pdev) if (!asic) return -ENOMEM; - spin_lock_init(&asic->lock); + raw_spin_lock_init(&asic->lock); platform_set_drvdata(pdev, asic); asic->dev = &pdev->dev; diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c new file mode 100644 index 000000000000..954cf0f66a31 --- /dev/null +++ b/drivers/mfd/atmel-smc.c @@ -0,0 +1,314 @@ +/* + * Atmel SMC (Static Memory Controller) helper functions. + * + * Copyright (C) 2017 Atmel + * Copyright (C) 2017 Free Electrons + * + * Author: Boris Brezillon <boris.brezillon@free-electrons.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/mfd/syscon/atmel-smc.h> + +/** + * atmel_smc_cs_conf_init - initialize a SMC CS conf + * @conf: the SMC CS conf to initialize + * + * Set all fields to 0 so that one can start defining a new config. + */ +void atmel_smc_cs_conf_init(struct atmel_smc_cs_conf *conf) +{ + memset(conf, 0, sizeof(*conf)); +} +EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_init); + +/** + * atmel_smc_cs_encode_ncycles - encode a number of MCK clk cycles in the + * format expected by the SMC engine + * @ncycles: number of MCK clk cycles + * @msbpos: position of the MSB part of the timing field + * @msbwidth: width of the MSB part of the timing field + * @msbfactor: factor applied to the MSB + * @encodedval: param used to store the encoding result + * + * This function encodes the @ncycles value as described in the datasheet + * (section "SMC Setup/Pulse/Cycle/Timings Register"). This is a generic + * helper which called with different parameter depending on the encoding + * scheme. + * + * If the @ncycles value is too big to be encoded, -ERANGE is returned and + * the encodedval is contains the maximum val. Otherwise, 0 is returned. + */ +static int atmel_smc_cs_encode_ncycles(unsigned int ncycles, + unsigned int msbpos, + unsigned int msbwidth, + unsigned int msbfactor, + unsigned int *encodedval) +{ + unsigned int lsbmask = GENMASK(msbpos - 1, 0); + unsigned int msbmask = GENMASK(msbwidth - 1, 0); + unsigned int msb, lsb; + int ret = 0; + + msb = ncycles / msbfactor; + lsb = ncycles % msbfactor; + + if (lsb > lsbmask) { + lsb = 0; + msb++; + } + + /* + * Let's just put the maximum we can if the requested setting does + * not fit in the register field. + * We still return -ERANGE in case the caller cares. + */ + if (msb > msbmask) { + msb = msbmask; + lsb = lsbmask; + ret = -ERANGE; + } + + *encodedval = (msb << msbpos) | lsb; + + return ret; +} + +/** + * atmel_smc_cs_conf_set_timing - set the SMC CS conf Txx parameter to a + * specific value + * @conf: SMC CS conf descriptor + * @shift: the position of the Txx field in the TIMINGS register + * @ncycles: value (expressed in MCK clk cycles) to assign to this Txx + * parameter + * + * This function encodes the @ncycles value as described in the datasheet + * (section "SMC Timings Register"), and then stores the result in the + * @conf->timings field at @shift position. + * + * Returns -EINVAL if shift is invalid, -ERANGE if ncycles does not fit in + * the field, and 0 otherwise. + */ +int atmel_smc_cs_conf_set_timing(struct atmel_smc_cs_conf *conf, + unsigned int shift, unsigned int ncycles) +{ + unsigned int val; + int ret; + + if (shift != ATMEL_HSMC_TIMINGS_TCLR_SHIFT && + shift != ATMEL_HSMC_TIMINGS_TADL_SHIFT && + shift != ATMEL_HSMC_TIMINGS_TAR_SHIFT && + shift != ATMEL_HSMC_TIMINGS_TRR_SHIFT && + shift != ATMEL_HSMC_TIMINGS_TWB_SHIFT) + return -EINVAL; + + /* + * The formula described in atmel datasheets (section "HSMC Timings + * Register"): + * + * ncycles = (Txx[3] * 64) + Txx[2:0] + */ + ret = atmel_smc_cs_encode_ncycles(ncycles, 3, 1, 64, &val); + conf->timings &= ~GENMASK(shift + 3, shift); + conf->timings |= val << shift; + + return ret; +} +EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_timing); + +/** + * atmel_smc_cs_conf_set_setup - set the SMC CS conf xx_SETUP parameter to a + * specific value + * @conf: SMC CS conf descriptor + * @shift: the position of the xx_SETUP field in the SETUP register + * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_SETUP + * parameter + * + * This function encodes the @ncycles value as described in the datasheet + * (section "SMC Setup Register"), and then stores the result in the + * @conf->setup field at @shift position. + * + * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in + * the field, and 0 otherwise. + */ +int atmel_smc_cs_conf_set_setup(struct atmel_smc_cs_conf *conf, + unsigned int shift, unsigned int ncycles) +{ + unsigned int val; + int ret; + + if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT && + shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT) + return -EINVAL; + + /* + * The formula described in atmel datasheets (section "SMC Setup + * Register"): + * + * ncycles = (128 * xx_SETUP[5]) + xx_SETUP[4:0] + */ + ret = atmel_smc_cs_encode_ncycles(ncycles, 5, 1, 128, &val); + conf->setup &= ~GENMASK(shift + 7, shift); + conf->setup |= val << shift; + + return ret; +} +EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_setup); + +/** + * atmel_smc_cs_conf_set_pulse - set the SMC CS conf xx_PULSE parameter to a + * specific value + * @conf: SMC CS conf descriptor + * @shift: the position of the xx_PULSE field in the PULSE register + * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_PULSE + * parameter + * + * This function encodes the @ncycles value as described in the datasheet + * (section "SMC Pulse Register"), and then stores the result in the + * @conf->setup field at @shift position. + * + * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in + * the field, and 0 otherwise. + */ +int atmel_smc_cs_conf_set_pulse(struct atmel_smc_cs_conf *conf, + unsigned int shift, unsigned int ncycles) +{ + unsigned int val; + int ret; + + if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT && + shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT) + return -EINVAL; + + /* + * The formula described in atmel datasheets (section "SMC Pulse + * Register"): + * + * ncycles = (256 * xx_PULSE[6]) + xx_PULSE[5:0] + */ + ret = atmel_smc_cs_encode_ncycles(ncycles, 6, 1, 256, &val); + conf->pulse &= ~GENMASK(shift + 7, shift); + conf->pulse |= val << shift; + + return ret; +} +EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_pulse); + +/** + * atmel_smc_cs_conf_set_cycle - set the SMC CS conf xx_CYCLE parameter to a + * specific value + * @conf: SMC CS conf descriptor + * @shift: the position of the xx_CYCLE field in the CYCLE register + * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_CYCLE + * parameter + * + * This function encodes the @ncycles value as described in the datasheet + * (section "SMC Pulse Register"), and then stores the result in the + * @conf->setup field at @shift position. + * + * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in + * the field, and 0 otherwise. + */ +int atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf *conf, + unsigned int shift, unsigned int ncycles) +{ + unsigned int val; + int ret; + + if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NRD_SHIFT) + return -EINV |
