Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp326399imm; Mon, 9 Jul 2018 02:27:44 -0700 (PDT) X-Google-Smtp-Source: AAOMgpeU42vO9eo/R14zhy1E4783RPu2ZQcf8tu69h9BWEeIzFwEKLiBEq+F/LF/qld/rQWA6ium X-Received: by 2002:a17:902:262:: with SMTP id 89-v6mr19974213plc.252.1531128464130; Mon, 09 Jul 2018 02:27:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531128464; cv=none; d=google.com; s=arc-20160816; b=PPB+64657VLiRbD9zie6rp9A4czEh6CcZDUUrGHi88XkSDKjmAM/KA/yszchxua/Tu DIy4SxAXGZdb4CZ9AInDoKLsaVdba0v5cg8kdboq+kQR3d9naPeBNmfRMxkXvNznCTgF bVghHmY8Fz6d2a2TQBIJieEKNk/ZylK5jMhUzeSNf9NoESn1XOB36wdOZ6hnGvcDzPNN FJep4SBKsetdESV2JKXp8jKGKSCJ83l/lB9yoSPwtmyXz5NgW3BsDzRvkO/R4JNzmqOv J77zbf9dIhT04LTzr2u/zmqh9QUlV/zxJMyk4cODzlE0HHxP6rRII0WfpJn+rdCDEjpH WCuA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature :arc-authentication-results; bh=1hifeIl42OufN1eNDMS/SneCDDtbeuphNImOZxIAQIU=; b=UmPOHQy3uk5UMcNCmwamkY8XLV8WMwDcX/WPJrY1EAr8Q+AMbODqg8rrYLnXSbm9K0 95z+uGQ4J5bnsSEdvypFL+/jOfzhtG28VaYx2tP5A8PvOb3Y11H1iDGL30rgCIg+WyQ1 n0k3+Qu+iP1zZbyuq928w1YLJPCYpfbwRWSDg2S9+SjAmW+fF1eaRED3V99pM11Abyxs ezBMxecKRXlP4vDErAlQ2tY2qJMVipwus7AW7LIsVduF3rjVH52dmgSVCCxUJLIhbAuH swqGsMd64kcp4U7PbUQVxAoAJH2jyU1XMe47hGN1mVwymyk2HZQyCM6vAoxPUH352c5Z Ul5g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=KtsMYaKi; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f5-v6si13733041plr.56.2018.07.09.02.27.29; Mon, 09 Jul 2018 02:27:44 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=KtsMYaKi; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754418AbeGIJ0Y (ORCPT + 99 others); Mon, 9 Jul 2018 05:26:24 -0400 Received: from mail-oi0-f66.google.com ([209.85.218.66]:43189 "EHLO mail-oi0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754214AbeGIJ0W (ORCPT ); Mon, 9 Jul 2018 05:26:22 -0400 Received: by mail-oi0-f66.google.com with SMTP id b15-v6so34562507oib.10 for ; Mon, 09 Jul 2018 02:26:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=1hifeIl42OufN1eNDMS/SneCDDtbeuphNImOZxIAQIU=; b=KtsMYaKilfudRnVip12fvSCcWltWKGWRld2WDGEpaf03fxLhVefM9BEthb97M1YcLX tiZ+IGIcPIFmoq2oQORx4eE7oc5ZGg5tAKfR2bLT3H7eFn+NT19nwK2pzSG5YBVaPbjb 87/7IzEVORfzxS5cDx2vSwtQRwkRyFGcMMYms= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=1hifeIl42OufN1eNDMS/SneCDDtbeuphNImOZxIAQIU=; b=OMNiBZooJEK7t5nwm6QuVTVyiVMJcd2N2/psGNOQpMtX/KoUfZP8cm1hld+RKYTfg0 pdHXO9fXfi4bR8FY301xaP1m/qKeKmni3/dyg/HR+RwvjSHw2bh6UfaaJtSZTdYExvRC mzSEZ/biniSVW8JpzHfQOz16Bks5EeeBO1XBjJOu75Ib3uypTfmTs9tPxN9WXzotq70K VGpY8bAc5q57Cs2lpQleW+laAZI41Bz+RcwMuZdg24ZdYw2eZPQtCP01yS8e0ed8B4iW FmC/j6fcTQvWhfFLoWfwF18S+/f1nhJos4nk2C4wkbLuYPZtC/RbC8/hOkjJNBCON6JE ku6Q== X-Gm-Message-State: APt69E1krbgcBVQNfOEvludlgAqX9rAY1YphY+T4s9uFrTzT1G/vNljb +aM4MGUiVBNELZUTJkE+eQGzH1+fU/HGsxUlTFIPHA== X-Received: by 2002:aca:e142:: with SMTP id y63-v6mr23361696oig.128.1531128381842; Mon, 09 Jul 2018 02:26:21 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a9d:237a:0:0:0:0:0 with HTTP; Mon, 9 Jul 2018 02:26:21 -0700 (PDT) In-Reply-To: References: From: Baolin Wang Date: Mon, 9 Jul 2018 17:26:21 +0800 Message-ID: Subject: Re: [PATCH v2 2/2] nvmem: Add Spreadtrum SC27XX efuse support To: Srinivas Kandagatla , Rob Herring , Mark Rutland Cc: Mark Brown , freeman.liu@spreadtrum.com, Baolin Wang , DTML , LKML Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Srinivas, On 25 June 2018 at 14:31, Baolin Wang wrote: > From: Freeman Liu > > This patch add the efuse driver which is embeded in Spreadtrum SC27XX > series PMICs. The sc27xx efuse contains 32 blocks and each block's > data width is 16 bits. > > Signed-off-by: Freeman Liu > Signed-off-by: Baolin Wang > --- > Changes since v1: > - Fix one typo. > --- Do you have any comments for this patch set? Thanks. > drivers/nvmem/Kconfig | 11 ++ > drivers/nvmem/Makefile | 3 +- > drivers/nvmem/sc27xx-efuse.c | 263 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 276 insertions(+), 1 deletion(-) > create mode 100644 drivers/nvmem/sc27xx-efuse.c > > diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig > index 54a3c29..0a7a470e 100644 > --- a/drivers/nvmem/Kconfig > +++ b/drivers/nvmem/Kconfig > @@ -181,4 +181,15 @@ config RAVE_SP_EEPROM > help > Say y here to enable Rave SP EEPROM support. > > +config SC27XX_EFUSE > + tristate "Spreadtrum SC27XX eFuse Support" > + depends on MFD_SC27XX_PMIC || COMPILE_TEST > + depends on HAS_IOMEM > + help > + This is a simple driver to dump specified values of Spreadtrum > + SC27XX PMICs from eFuse. > + > + This driver can also be built as a module. If so, the module > + will be called nvmem-sc27xx-efuse. > + > endif > diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile > index 27e96a8..4e8c616 100644 > --- a/drivers/nvmem/Makefile > +++ b/drivers/nvmem/Makefile > @@ -39,4 +39,5 @@ obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o > nvmem_snvs_lpgpr-y := snvs_lpgpr.o > obj-$(CONFIG_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o > nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o > - > +obj-$(CONFIG_SC27XX_EFUSE) += nvmem-sc27xx-efuse.o > +nvmem-sc27xx-efuse-y := sc27xx-efuse.o > diff --git a/drivers/nvmem/sc27xx-efuse.c b/drivers/nvmem/sc27xx-efuse.c > new file mode 100644 > index 0000000..07c210c > --- /dev/null > +++ b/drivers/nvmem/sc27xx-efuse.c > @@ -0,0 +1,263 @@ > +// SPDX-License-Identifier: GPL-2.0 > +// Copyright (C) 2018 Spreadtrum Communications Inc. > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +/* PMIC global registers definition */ > +#define SC27XX_MODULE_EN 0xc08 > +#define SC27XX_EFUSE_EN BIT(6) > + > +/* Efuse controller registers definition */ > +#define SC27XX_EFUSE_GLB_CTRL 0x0 > +#define SC27XX_EFUSE_DATA_RD 0x4 > +#define SC27XX_EFUSE_DATA_WR 0x8 > +#define SC27XX_EFUSE_BLOCK_INDEX 0xc > +#define SC27XX_EFUSE_MODE_CTRL 0x10 > +#define SC27XX_EFUSE_STATUS 0x14 > +#define SC27XX_EFUSE_WR_TIMING_CTRL 0x20 > +#define SC27XX_EFUSE_RD_TIMING_CTRL 0x24 > +#define SC27XX_EFUSE_EFUSE_DEB_CTRL 0x28 > + > +/* Mask definition for SC27XX_EFUSE_BLOCK_INDEX register */ > +#define SC27XX_EFUSE_BLOCK_MASK GENMASK(4, 0) > + > +/* Bits definitions for SC27XX_EFUSE_MODE_CTRL register */ > +#define SC27XX_EFUSE_PG_START BIT(0) > +#define SC27XX_EFUSE_RD_START BIT(1) > +#define SC27XX_EFUSE_CLR_RDDONE BIT(2) > + > +/* Bits definitions for SC27XX_EFUSE_STATUS register */ > +#define SC27XX_EFUSE_PGM_BUSY BIT(0) > +#define SC27XX_EFUSE_READ_BUSY BIT(1) > +#define SC27XX_EFUSE_STANDBY BIT(2) > +#define SC27XX_EFUSE_GLOBAL_PROT BIT(3) > +#define SC27XX_EFUSE_RD_DONE BIT(4) > + > +/* Block number and block width (bytes) definitions */ > +#define SC27XX_EFUSE_BLOCK_MAX 32 > +#define SC27XX_EFUSE_BLOCK_WIDTH 2 > + > +/* Timeout (ms) for the trylock of hardware spinlocks */ > +#define SC27XX_EFUSE_HWLOCK_TIMEOUT 5000 > + > +/* Timeout (us) of polling the status */ > +#define SC27XX_EFUSE_POLL_TIMEOUT 3000000 > +#define SC27XX_EFUSE_POLL_DELAY_US 10000 > + > +struct sc27xx_efuse { > + struct device *dev; > + struct regmap *regmap; > + struct hwspinlock *hwlock; > + struct mutex mutex; > + u32 base; > +}; > + > +/* > + * On Spreadtrum platform, we have multi-subsystems will access the unique > + * efuse controller, so we need one hardware spinlock to synchronize between > + * the multiple subsystems. > + */ > +static int sc27xx_efuse_lock(struct sc27xx_efuse *efuse) > +{ > + int ret; > + > + mutex_lock(&efuse->mutex); > + > + ret = hwspin_lock_timeout_raw(efuse->hwlock, > + SC27XX_EFUSE_HWLOCK_TIMEOUT); > + if (ret) { > + dev_err(efuse->dev, "timeout to get the hwspinlock\n"); > + mutex_unlock(&efuse->mutex); > + return ret; > + } > + > + return 0; > +} > + > +static void sc27xx_efuse_unlock(struct sc27xx_efuse *efuse) > +{ > + hwspin_unlock_raw(efuse->hwlock); > + mutex_unlock(&efuse->mutex); > +} > + > +static int sc27xx_efuse_poll_status(struct sc27xx_efuse *efuse, u32 bits) > +{ > + int ret; > + u32 val; > + > + ret = regmap_read_poll_timeout(efuse->regmap, > + efuse->base + SC27XX_EFUSE_STATUS, > + val, (val & bits), > + SC27XX_EFUSE_POLL_DELAY_US, > + SC27XX_EFUSE_POLL_TIMEOUT); > + if (ret) { > + dev_err(efuse->dev, "timeout to update the efuse status\n"); > + return ret; > + } > + > + return 0; > +} > + > +static int sc27xx_efuse_read(void *context, u32 offset, void *val, size_t bytes) > +{ > + struct sc27xx_efuse *efuse = context; > + u32 buf; > + int ret; > + > + if (offset > SC27XX_EFUSE_BLOCK_MAX || bytes > SC27XX_EFUSE_BLOCK_WIDTH) > + return -EINVAL; > + > + ret = sc27xx_efuse_lock(efuse); > + if (ret) > + return ret; > + > + /* Enable the efuse controller. */ > + ret = regmap_update_bits(efuse->regmap, SC27XX_MODULE_EN, > + SC27XX_EFUSE_EN, SC27XX_EFUSE_EN); > + if (ret) > + goto unlock_efuse; > + > + /* > + * Before reading, we should ensure the efuse controller is in > + * standby state. > + */ > + ret = sc27xx_efuse_poll_status(efuse, SC27XX_EFUSE_STANDBY); > + if (ret) > + goto disable_efuse; > + > + /* Set the block address to be read. */ > + ret = regmap_write(efuse->regmap, efuse->base + SC27XX_EFUSE_BLOCK_INDEX, > + offset & SC27XX_EFUSE_BLOCK_MASK); > + if (ret) > + goto disable_efuse; > + > + /* Start reading process from efuse memory. */ > + ret = regmap_update_bits(efuse->regmap, > + efuse->base + SC27XX_EFUSE_MODE_CTRL, > + SC27XX_EFUSE_RD_START, > + SC27XX_EFUSE_RD_START); > + if (ret) > + goto disable_efuse; > + > + /* > + * Polling the read done status to make sure the reading process > + * is completed, that means the data can be read out now. > + */ > + ret = sc27xx_efuse_poll_status(efuse, SC27XX_EFUSE_RD_DONE); > + if (ret) > + goto disable_efuse; > + > + /* Read data from efuse memory. */ > + ret = regmap_read(efuse->regmap, efuse->base + SC27XX_EFUSE_DATA_RD, > + &buf); > + if (ret) > + goto disable_efuse; > + > + /* Clear the read done flag. */ > + ret = regmap_update_bits(efuse->regmap, > + efuse->base + SC27XX_EFUSE_MODE_CTRL, > + SC27XX_EFUSE_CLR_RDDONE, > + SC27XX_EFUSE_CLR_RDDONE); > + > +disable_efuse: > + /* Disable the efuse controller after reading. */ > + regmap_update_bits(efuse->regmap, SC27XX_MODULE_EN, SC27XX_EFUSE_EN, 0); > +unlock_efuse: > + sc27xx_efuse_unlock(efuse); > + > + if (!ret) > + memcpy(val, &buf, bytes); > + > + return ret; > +} > + > +static int sc27xx_efuse_probe(struct platform_device *pdev) > +{ > + struct device_node *np = pdev->dev.of_node; > + struct nvmem_config econfig = { }; > + struct nvmem_device *nvmem; > + struct sc27xx_efuse *efuse; > + int ret; > + > + efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL); > + if (!efuse) > + return -ENOMEM; > + > + efuse->regmap = dev_get_regmap(pdev->dev.parent, NULL); > + if (!efuse->regmap) { > + dev_err(&pdev->dev, "failed to get efuse regmap\n"); > + return -ENODEV; > + } > + > + ret = of_property_read_u32(np, "reg", &efuse->base); > + if (ret) { > + dev_err(&pdev->dev, "failed to get efuse base address\n"); > + return ret; > + } > + > + ret = of_hwspin_lock_get_id(np, 0); > + if (ret < 0) { > + dev_err(&pdev->dev, "failed to get hwspinlock id\n"); > + return ret; > + } > + > + efuse->hwlock = hwspin_lock_request_specific(ret); > + if (!efuse->hwlock) { > + dev_err(&pdev->dev, "failed to request hwspinlock\n"); > + return -ENXIO; > + } > + > + mutex_init(&efuse->mutex); > + efuse->dev = &pdev->dev; > + platform_set_drvdata(pdev, efuse); > + > + econfig.stride = 1; > + econfig.word_size = 1; > + econfig.read_only = true; > + econfig.name = "sc27xx-efuse"; > + econfig.size = SC27XX_EFUSE_BLOCK_MAX * SC27XX_EFUSE_BLOCK_WIDTH; > + econfig.reg_read = sc27xx_efuse_read; > + econfig.priv = efuse; > + econfig.dev = &pdev->dev; > + nvmem = devm_nvmem_register(&pdev->dev, &econfig); > + if (IS_ERR(nvmem)) { > + dev_err(&pdev->dev, "failed to register nvmem config\n"); > + hwspin_lock_free(efuse->hwlock); > + return PTR_ERR(nvmem); > + } > + > + return 0; > +} > + > +static int sc27xx_efuse_remove(struct platform_device *pdev) > +{ > + struct sc27xx_efuse *efuse = platform_get_drvdata(pdev); > + > + hwspin_lock_free(efuse->hwlock); > + return 0; > +} > + > +static const struct of_device_id sc27xx_efuse_of_match[] = { > + { .compatible = "sprd,sc2731-efuse" }, > + { } > +}; > + > +static struct platform_driver sc27xx_efuse_driver = { > + .probe = sc27xx_efuse_probe, > + .remove = sc27xx_efuse_remove, > + .driver = { > + .name = "sc27xx-efuse", > + .of_match_table = sc27xx_efuse_of_match, > + }, > +}; > + > +module_platform_driver(sc27xx_efuse_driver); > + > +MODULE_AUTHOR("Freeman Liu "); > +MODULE_DESCRIPTION("Spreadtrum SC27xx efuse driver"); > +MODULE_LICENSE("GPL v2"); > -- > 1.7.9.5 > -- Baolin Wang Best Regards