From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Wed, 11 Jan 2023 18:44:32 +0100 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by lore.white.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1pFf9N-0091pW-Hl for lore@lore.pengutronix.de; Wed, 11 Jan 2023 18:44:32 +0100 Received: from bombadil.infradead.org ([2607:7c80:54:3::133]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pFf9K-0006W0-Ii for lore@pengutronix.de; Wed, 11 Jan 2023 18:44:32 +0100 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=+ihRNAeGslyNt1P0B9swf9AVFNDXW4D4D6jl+ojPe50=; b=uG2xbsv4QbXimxJc13FPiVeqMm hbnXrO/KFZYfL9+QYVOF+iAotATGEsz1NiZaWIWkUVBvgSliahuMqIRLD6bq4jfJNhLyF6wVVfJbX 2mMp5H+mjiPzWlVYy35Y8uFjTO409SLyMdZPy/gAlgf0fl2Aizfr78mGE1WytXgcTjy5yl9MjoBAh T8KmXEXlQWXOy6kz8bZz93op0Vq9Z/9Kd4VaO1gnEP1crN6ZpiiB/qWO9DrzL/qHfowAY80dOZ+wb dki+tJhi9XcKv43HrredmEFq6745rZayAW2TTeFjUnpiC4WfhgARwn+Kd9k5fD4BompvHoLcSUCHx RuLfWnLA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pFf7j-00CUbp-Mp; Wed, 11 Jan 2023 17:42:52 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pFf5a-00CTNw-Et for barebox@lists.infradead.org; Wed, 11 Jan 2023 17:40:45 +0000 Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pFf5R-000537-67; Wed, 11 Jan 2023 18:40:29 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtp (Exim 4.94.2) (envelope-from ) id 1pFf5Q-005M6O-EX; Wed, 11 Jan 2023 18:40:28 +0100 Received: from afa by dude04.red.stw.pengutronix.de with local (Exim 4.94.2) (envelope-from ) id 1pFf5O-007DGc-HX; Wed, 11 Jan 2023 18:40:26 +0100 From: Ahmad Fatoum To: barebox@lists.infradead.org Cc: Ahmad Fatoum Date: Wed, 11 Jan 2023 18:40:19 +0100 Message-Id: <20230111174023.1719129-12-a.fatoum@pengutronix.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230111174023.1719129-1-a.fatoum@pengutronix.de> References: <20230111174023.1719129-1-a.fatoum@pengutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230111_094038_927934_9C0DBDA5 X-CRM114-Status: GOOD ( 25.81 ) X-BeenThere: barebox@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "barebox" X-SA-Exim-Connect-IP: 2607:7c80:54:3::133 X-SA-Exim-Mail-From: barebox-bounces+lore=pengutronix.de@lists.infradead.org X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on metis.ext.pengutronix.de X-Spam-Level: X-Spam-Status: No, score=-4.7 required=4.0 tests=AWL,BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,SPF_HELO_NONE,SPF_NONE autolearn=unavailable autolearn_force=no version=3.4.2 Subject: [PATCH 11/15] mfd: add atmel-smc driver X-SA-Exim-Version: 4.2.1 (built Wed, 08 May 2019 21:11:16 +0000) X-SA-Exim-Scanned: Yes (on metis.ext.pengutronix.de) Port over the Linux Atmel Static Memory Controller driver for use by the incoming update to the Atmel NAND controller driver Signed-off-by: Ahmad Fatoum --- drivers/mfd/Kconfig | 4 + drivers/mfd/Makefile | 1 + drivers/mfd/atmel-smc.c | 352 +++++++++++++++++++++++++++ include/linux/mfd/syscon/atmel-smc.h | 119 +++++++++ 4 files changed, 476 insertions(+) create mode 100644 drivers/mfd/atmel-smc.c create mode 100644 include/linux/mfd/syscon/atmel-smc.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index c33fa262236c..f1f7e27fadfe 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -129,4 +129,8 @@ config MFD_AXP20X_I2C management ICs (PMICs) controlled with I2C. This driver currently only provide a character device in /dev. +config MFD_ATMEL_SMC + bool + select MFD_SYSCON + endmenu diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index a3cb90e88346..b89ddab5947d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o obj-$(CONFIG_MFD_RK808) += rk808.o obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o axp20x.o +obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c new file mode 100644 index 000000000000..ed24ef650f5b --- /dev/null +++ b/drivers/mfd/atmel-smc.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Atmel SMC (Static Memory Controller) helper functions. + * + * Copyright (C) 2017 Atmel + * Copyright (C) 2017 Free Electrons + * + * Author: Boris Brezillon + */ + +#include +#include +#include + +/** + * 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 Cycle 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 -EINVAL; + + /* + * The formula described in atmel datasheets (section "SMC Cycle + * Register"): + * + * ncycles = (xx_CYCLE[8:7] * 256) + xx_CYCLE[6:0] + */ + ret = atmel_smc_cs_encode_ncycles(ncycles, 7, 2, 256, &val); + conf->cycle &= ~GENMASK(shift + 15, shift); + conf->cycle |= val << shift; + + return ret; +} +EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle); + +/** + * atmel_smc_cs_conf_apply - apply an SMC CS conf + * @regmap: the SMC regmap + * @cs: the CS id + * @conf: the SMC CS conf to apply + * + * Applies an SMC CS configuration. + * Only valid on at91sam9/avr32 SoCs. + */ +void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs, + const struct atmel_smc_cs_conf *conf) +{ + regmap_write(regmap, ATMEL_SMC_SETUP(cs), conf->setup); + regmap_write(regmap, ATMEL_SMC_PULSE(cs), conf->pulse); + regmap_write(regmap, ATMEL_SMC_CYCLE(cs), conf->cycle); + regmap_write(regmap, ATMEL_SMC_MODE(cs), conf->mode); +} +EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply); + +/** + * atmel_hsmc_cs_conf_apply - apply an SMC CS conf + * @regmap: the HSMC regmap + * @cs: the CS id + * @layout: the layout of registers + * @conf: the SMC CS conf to apply + * + * Applies an SMC CS configuration. + * Only valid on post-sama5 SoCs. + */ +void atmel_hsmc_cs_conf_apply(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *layout, + int cs, const struct atmel_smc_cs_conf *conf) +{ + regmap_write(regmap, ATMEL_HSMC_SETUP(layout, cs), conf->setup); + regmap_write(regmap, ATMEL_HSMC_PULSE(layout, cs), conf->pulse); + regmap_write(regmap, ATMEL_HSMC_CYCLE(layout, cs), conf->cycle); + regmap_write(regmap, ATMEL_HSMC_TIMINGS(layout, cs), conf->timings); + regmap_write(regmap, ATMEL_HSMC_MODE(layout, cs), conf->mode); +} +EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply); + +/** + * atmel_smc_cs_conf_get - retrieve the current SMC CS conf + * @regmap: the SMC regmap + * @cs: the CS id + * @conf: the SMC CS conf object to store the current conf + * + * Retrieve the SMC CS configuration. + * Only valid on at91sam9/avr32 SoCs. + */ +void atmel_smc_cs_conf_get(struct regmap *regmap, int cs, + struct atmel_smc_cs_conf *conf) +{ + regmap_read(regmap, ATMEL_SMC_SETUP(cs), &conf->setup); + regmap_read(regmap, ATMEL_SMC_PULSE(cs), &conf->pulse); + regmap_read(regmap, ATMEL_SMC_CYCLE(cs), &conf->cycle); + regmap_read(regmap, ATMEL_SMC_MODE(cs), &conf->mode); +} +EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get); + +/** + * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf + * @regmap: the HSMC regmap + * @cs: the CS id + * @layout: the layout of registers + * @conf: the SMC CS conf object to store the current conf + * + * Retrieve the SMC CS configuration. + * Only valid on post-sama5 SoCs. + */ +void atmel_hsmc_cs_conf_get(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *layout, + int cs, struct atmel_smc_cs_conf *conf) +{ + regmap_read(regmap, ATMEL_HSMC_SETUP(layout, cs), &conf->setup); + regmap_read(regmap, ATMEL_HSMC_PULSE(layout, cs), &conf->pulse); + regmap_read(regmap, ATMEL_HSMC_CYCLE(layout, cs), &conf->cycle); + regmap_read(regmap, ATMEL_HSMC_TIMINGS(layout, cs), &conf->timings); + regmap_read(regmap, ATMEL_HSMC_MODE(layout, cs), &conf->mode); +} +EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get); + +static const struct atmel_hsmc_reg_layout sama5d3_reg_layout = { + .timing_regs_offset = 0x600, +}; + +static const struct atmel_hsmc_reg_layout sama5d2_reg_layout = { + .timing_regs_offset = 0x700, +}; + +static const struct of_device_id atmel_smc_ids[] = { + { .compatible = "atmel,at91sam9260-smc", .data = NULL }, + { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout }, + { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout }, + { /* sentinel */ }, +}; + +/** + * atmel_hsmc_get_reg_layout - retrieve the layout of HSMC registers + * @np: the HSMC regmap + * + * Retrieve the layout of HSMC registers. + * + * Returns NULL in case of SMC, a struct atmel_hsmc_reg_layout pointer + * in HSMC case, otherwise ERR_PTR(-EINVAL). + */ +const struct atmel_hsmc_reg_layout * +atmel_hsmc_get_reg_layout(struct device_node *np) +{ + const struct of_device_id *match; + + match = of_match_node(atmel_smc_ids, np); + + return match ? match->data : ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(atmel_hsmc_get_reg_layout); diff --git a/include/linux/mfd/syscon/atmel-smc.h b/include/linux/mfd/syscon/atmel-smc.h new file mode 100644 index 000000000000..881edefe4e9c --- /dev/null +++ b/include/linux/mfd/syscon/atmel-smc.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Atmel SMC (Static Memory Controller) register offsets and bit definitions. + * + * Copyright (C) 2014 Atmel + * Copyright (C) 2014 Free Electrons + * + * Author: Boris Brezillon + */ + +#ifndef _LINUX_MFD_SYSCON_ATMEL_SMC_H_ +#define _LINUX_MFD_SYSCON_ATMEL_SMC_H_ + +#include +#include +#include + +#define ATMEL_SMC_SETUP(cs) (((cs) * 0x10)) +#define ATMEL_HSMC_SETUP(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14)) +#define ATMEL_SMC_PULSE(cs) (((cs) * 0x10) + 0x4) +#define ATMEL_HSMC_PULSE(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14) + 0x4) +#define ATMEL_SMC_CYCLE(cs) (((cs) * 0x10) + 0x8) +#define ATMEL_HSMC_CYCLE(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14) + 0x8) +#define ATMEL_SMC_NWE_SHIFT 0 +#define ATMEL_SMC_NCS_WR_SHIFT 8 +#define ATMEL_SMC_NRD_SHIFT 16 +#define ATMEL_SMC_NCS_RD_SHIFT 24 + +#define ATMEL_SMC_MODE(cs) (((cs) * 0x10) + 0xc) +#define ATMEL_HSMC_MODE(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14) + 0x10) +#define ATMEL_SMC_MODE_READMODE_MASK BIT(0) +#define ATMEL_SMC_MODE_READMODE_NCS (0 << 0) +#define ATMEL_SMC_MODE_READMODE_NRD (1 << 0) +#define ATMEL_SMC_MODE_WRITEMODE_MASK BIT(1) +#define ATMEL_SMC_MODE_WRITEMODE_NCS (0 << 1) +#define ATMEL_SMC_MODE_WRITEMODE_NWE (1 << 1) +#define ATMEL_SMC_MODE_EXNWMODE_MASK GENMASK(5, 4) +#define ATMEL_SMC_MODE_EXNWMODE_DISABLE (0 << 4) +#define ATMEL_SMC_MODE_EXNWMODE_FROZEN (2 << 4) +#define ATMEL_SMC_MODE_EXNWMODE_READY (3 << 4) +#define ATMEL_SMC_MODE_BAT_MASK BIT(8) +#define ATMEL_SMC_MODE_BAT_SELECT (0 << 8) +#define ATMEL_SMC_MODE_BAT_WRITE (1 << 8) +#define ATMEL_SMC_MODE_DBW_MASK GENMASK(13, 12) +#define ATMEL_SMC_MODE_DBW_8 (0 << 12) +#define ATMEL_SMC_MODE_DBW_16 (1 << 12) +#define ATMEL_SMC_MODE_DBW_32 (2 << 12) +#define ATMEL_SMC_MODE_TDF_MASK GENMASK(19, 16) +#define ATMEL_SMC_MODE_TDF(x) (((x) - 1) << 16) +#define ATMEL_SMC_MODE_TDF_MAX 16 +#define ATMEL_SMC_MODE_TDF_MIN 1 +#define ATMEL_SMC_MODE_TDFMODE_OPTIMIZED BIT(20) +#define ATMEL_SMC_MODE_PMEN BIT(24) +#define ATMEL_SMC_MODE_PS_MASK GENMASK(29, 28) +#define ATMEL_SMC_MODE_PS_4 (0 << 28) +#define ATMEL_SMC_MODE_PS_8 (1 << 28) +#define ATMEL_SMC_MODE_PS_16 (2 << 28) +#define ATMEL_SMC_MODE_PS_32 (3 << 28) + +#define ATMEL_HSMC_TIMINGS(layout, cs) \ + ((layout)->timing_regs_offset + ((cs) * 0x14) + 0xc) +#define ATMEL_HSMC_TIMINGS_OCMS BIT(12) +#define ATMEL_HSMC_TIMINGS_RBNSEL(x) ((x) << 28) +#define ATMEL_HSMC_TIMINGS_NFSEL BIT(31) +#define ATMEL_HSMC_TIMINGS_TCLR_SHIFT 0 +#define ATMEL_HSMC_TIMINGS_TADL_SHIFT 4 +#define ATMEL_HSMC_TIMINGS_TAR_SHIFT 8 +#define ATMEL_HSMC_TIMINGS_TRR_SHIFT 16 +#define ATMEL_HSMC_TIMINGS_TWB_SHIFT 24 + +struct atmel_hsmc_reg_layout { + unsigned int timing_regs_offset; +}; + +/** + * struct atmel_smc_cs_conf - SMC CS config as described in the datasheet. + * @setup: NCS/NWE/NRD setup timings (not applicable to at91rm9200) + * @pulse: NCS/NWE/NRD pulse timings (not applicable to at91rm9200) + * @cycle: NWE/NRD cycle timings (not applicable to at91rm9200) + * @timings: advanced NAND related timings (only applicable to HSMC) + * @mode: all kind of config parameters (see the fields definition above). + * The mode fields are different on at91rm9200 + */ +struct atmel_smc_cs_conf { + u32 setup; + u32 pulse; + u32 cycle; + u32 timings; + u32 mode; +}; + +void atmel_smc_cs_conf_init(struct atmel_smc_cs_conf *conf); +int atmel_smc_cs_conf_set_timing(struct atmel_smc_cs_conf *conf, + unsigned int shift, + unsigned int ncycles); +int atmel_smc_cs_conf_set_setup(struct atmel_smc_cs_conf *conf, + unsigned int shift, unsigned int ncycles); +int atmel_smc_cs_conf_set_pulse(struct atmel_smc_cs_conf *conf, + unsigned int shift, unsigned int ncycles); +int atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf *conf, + unsigned int shift, unsigned int ncycles); +void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs, + const struct atmel_smc_cs_conf *conf); +void atmel_hsmc_cs_conf_apply(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *reglayout, + int cs, const struct atmel_smc_cs_conf *conf); +void atmel_smc_cs_conf_get(struct regmap *regmap, int cs, + struct atmel_smc_cs_conf *conf); +void atmel_hsmc_cs_conf_get(struct regmap *regmap, + const struct atmel_hsmc_reg_layout *reglayout, + int cs, struct atmel_smc_cs_conf *conf); +const struct atmel_hsmc_reg_layout * +atmel_hsmc_get_reg_layout(struct device_node *np); + +#endif /* _LINUX_MFD_SYSCON_ATMEL_SMC_H_ */ -- 2.30.2