From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CC3E542B313 for ; Fri, 17 Jul 2026 14:32:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784298729; cv=none; b=MMM0ub2gwVTx3fjtQN2gAlUDcwS9oNZJ7Uc5sQh2hoQA6zRrODM6QK1DyflhjYcrw1NFM7CeWUlBSAOThhoi5z2TjkUHb+AKIveAS/fixWMAy6Z4kdXyc/fM/1krqd4h0PBYc+YxzL1EqsBSndxkeOwoSfhZ+jhETBQO7Ah4dmg= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784298729; c=relaxed/simple; bh=sPyPkKkA7B6OSHuLq+IOkQW1+TpMgs8cUjWHQQWzW20=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=biUCh7XFBVkm8/WH2T+1Dg5bFw1FtLP9LcQwEG+GI6gQftOe5HSITCG8o9fSiosW8GrZnRAKDZoBrh0U/DkenJgpVotJs7gVvj1qouGKDa8ajKkqOMRFQPikrrxc8kyZ7utRZY+lNozKg1GTkhvrkmBEPSq9uvEBL6P0wiHVavk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b=FnuWK8nA; arc=none smtp.client-ip=209.85.128.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre.com header.i=@baylibre.com header.b="FnuWK8nA" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-493ce08a75bso32551665e9.1 for ; Fri, 17 Jul 2026 07:32:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre.com; s=google; t=1784298725; x=1784903525; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=R5kUjSYYkjpDH6Vg3nnJ0fk0+aFrx51UmVjPW4elpks=; b=FnuWK8nAPSXUWQ8Amvgq56Z/VWNPKpgOiimBzdQ9HHsRjy//u5JYlnoAbWNHYOUMyF 2r18WUKHhmyXeKrdJGjpePao/jfro22vjbdXey7Tm9uElJFSoTFirICDTBO0XLNfq944 I+DghsHGcyD79vv39v6mVpfA3v5tFthobTLGCOsgFwdnn0Xk3m7BYL6bhlCBULfFUner m1MMZC7IKEJeoBEY19tWfD3vX9bQKEmwL73i91GVR/DYBIq/kwKgjT3oOPTSIYJP/t9i Hyo0InitXQjArqskgS5Rhh+tcd880Ez9G3lOex296J4ulzc0+p1xEukNvnpQKsOo4CWD 61Uw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784298725; x=1784903525; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=R5kUjSYYkjpDH6Vg3nnJ0fk0+aFrx51UmVjPW4elpks=; b=lvt2eBUZvoFN4OT/z92JN1212p7Zsg1PvStwuRjMNiqpSf3dA0MlZ37jmojY7hcJkr 6rJfCpREHCnaki7GS5tcPRQGgQT4j5XQBIGJ8IFOqZvL+ztQTpn+WmfdoE7y66iMO2dp U6/O1Cd8x/pjxS/SCDA9LFxN4dgPhU/x5hU3QUHaUVIXzhFWGFkpREozdvuqNwMcWvmu WsMdMKJjSjm/8kd9mH7kavhpISxcA+0J9sPSf1asxUOYWw8SGpT58yCC+txzaedPR4yK 8aV4VaZAouLai392o5gMWJ04vvnUvdVu8n2PxUBaCt6UNwbrzh2w8hNF5+/M4Mpvtx8F fVNg== X-Forwarded-Encrypted: i=1; AHgh+RooMsIxXFj7sMei5EemCAavaGA+IZbxrkIuFcEiNBi5NiPfe8qNkDZe7CyRlq/FN/RLw8GlieHdWMF/lEo=@vger.kernel.org X-Gm-Message-State: AOJu0YyejU6tfSFNzVngGjJ0veA4ye2OgTwF6TkVcToKF5RCdIFfUiJV 2sfTJC5Ung1Gz1Nx6ojJfnhPnsSyDMQJ+/Me2Jqe+poFjZm6wZZbACwVlnUFmumdSb4= X-Gm-Gg: AfdE7ck637Cdq8feFEZTrtJT3qNpa6wlwxpLQLen70yZSNS/+S0dHvoWpHvAK67dfxo jcbJnDLV156VH5o4tn1kL86qaCz2WN936mpdBZUrXEFQXF6SqiF7uPSRzj5S2YoOXXANDMP3qqe Bmgiw47BjyAHuIlnBWsMQjmaSFE9nvrf79PRcLxzVkv4RzMNs0kZufKRVMdgDaUBXUU5NPJZ78t Fn3bc4j28r3ZlP9LZha0CblwnB/035o3ozRIgMNiChKB1nbugib/d7OVxDCTBnozg0ezfJtKfyp 5mEYib/KeyjcztXmLfUHjDy3MlezDOMnxcGHgwXzi8Jk3mVL6R6o5wVGcu2fhgXMnw618t1+Cwm 2uD2bV+edOUh8bXd8LvZHhXr0JaS3cM9MWyh56eu+2rfHjpEGNBUV6qPcXjAeml6w2yTXN6bRK/ le X-Received: by 2002:a05:600c:3512:b0:493:cfe8:5b36 with SMTP id 5b1f17b1804b1-4954a3eec4bmr37133505e9.8.1784298724975; Fri, 17 Jul 2026 07:32:04 -0700 (PDT) Received: from localhost ([2a01:e0a:3c5:5fb1:8e22:8a15:f33f:dc60]) by smtp.gmail.com with UTF8SMTPSA id 5b1f17b1804b1-495499d1d4asm36014595e9.2.2026.07.17.07.32.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jul 2026 07:32:03 -0700 (PDT) From: Jerome Brunet Date: Fri, 17 Jul 2026 16:31:27 +0200 Subject: [PATCH v4 5/5] regulator: axp20x: add support for the AXP318W Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260717-axp318-regulator-v4-5-50aff97084dd@baylibre.com> References: <20260717-axp318-regulator-v4-0-50aff97084dd@baylibre.com> In-Reply-To: <20260717-axp318-regulator-v4-0-50aff97084dd@baylibre.com> To: Andre Przywara , Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Liam Girdwood , Mark Brown Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Jerome Brunet X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=21093; i=jbrunet@baylibre.com; h=from:subject:message-id; bh=6aWVgGJ9syvPUIAv3daQmyMDpN9KF/7cWr0tcqwN8WM=; b=owEBbQKS/ZANAwAKAeb8Dxw38tqFAcsmYgBqWjzSp2uR0Nqr44pA5bCdbQq0KR1htjvvYgfSb I+IdFH5klaJAjMEAAEKAB0WIQT04VmuGPP1bV8btxvm/A8cN/LahQUCalo80gAKCRDm/A8cN/La hSgvEACdJM2y1dWWLiZW7RdYuGiYNmZjr2DkxGKUtwyu0g+NDiNaapV1gJXB/C9809/7OIruRJ4 Kc+PmoehhdV8josAGbUS9BC+DBMsGMxhvAKmP25bXYBRP2wIukQcD0jk17XS3ewyhQ5ng9PgCpn Xcy4B6ahZNGMPmyYqCS1wyiROIP6KSW97GA9/CUlrIeZbI+btYY9VuLRr12pYuoxmF77wRTcJsh MjA8M98XrTePuIrbGXLyBjyAcVUDOV8yQcXRcf+X5OO/HsiSCTNGJbRKxbsa3h+UNDShDJsAp3E LsUBziPj1PdD1okuw5SF4iH3r+6xicpKNS1u9DA/Q8W6TPssCZ4nr/0111DSlLUfA05fhIJrXRx 3XZOZQXv3pZEKEqqVCMFvTEESb0y2fldV2Tb1H7BLbX3OG46+XwcpmC9ibPzMDhTQIpDnOKlJRR d0gW0O9oMB1NJp/O/13IcvlYT0m0NfZ8k13csvFsaAMILzJIub7mLeEST+ifXzOBLXXwiTF42yL vaUi+QcuhcvVdOZxoFbI5aWp5TI6T08GNLH6ykUyljaTBFsslFCslkdaEpoSQhOYS/824FkqrhR BcO8tID53jgeOh/p8RwS+u/YHhPJCHheOEDXtkYfzUrXrNaeiUZECLOcyqzjKu9Yeb/QVdOLBPa 1vSImZMNnRKLuOA== X-Developer-Key: i=jbrunet@baylibre.com; a=openpgp; fpr=F29F26CF27BAE1A9719AE6BDC3C92AAF3E60AED9 From: Andre Przywara The X-Powers AXP318W is a typical PMIC from X-Powers, featuring nine DC/DC converters and 28 LDOs, on the regulator side. Describe the chip's voltage settings and switch registers, how the voltages are encoded, and connect this to the MFD device via its regulator ID. We use just "318" for the internal identifiers, for easier typing and less churn. If something else other than the "AXP318W" shows up, that's an easy change, externally visible strings carry the additional letter already. Reviewed-by: Mark Brown Signed-off-by: Andre Przywara Co-developed-by: Jerome Brunet Signed-off-by: Jerome Brunet --- drivers/regulator/axp20x-regulator.c | 326 ++++++++++++++++++++++++++++++++++- include/linux/mfd/axp20x.h | 45 +++++ 2 files changed, 362 insertions(+), 9 deletions(-) diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index da891415efc0..8f6d28a1f76f 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -138,6 +138,30 @@ #define AXP313A_DCDC_V_OUT_MASK GENMASK(6, 0) #define AXP313A_LDO_V_OUT_MASK GENMASK(4, 0) +#define AXP318_DCDC1_PFM_PWM_CTRL BIT(7) +#define AXP318_DCDC23_POLYPHASE_CTRL BIT(6) +#define AXP318_DCDC45_POLYPHASE_CTRL BIT(7) +#define AXP318_DCDC1_V_OUT_MASK GENMASK(4, 0) +#define AXP318_DCDC2_V_OUT_MASK GENMASK(6, 0) +#define AXP318_LDO_V_OUT_MASK GENMASK(4, 0) +#define AXP318_ELDO_V_OUT_MASK GENMASK(5, 0) +#define AXP318_THRESHOLD_VOLTAGE 1540000 +/* + * FIXME: + * Some LDOs of the AXP318 may be fed by different supplies and + * the documentation repeatedly warns that output voltage must + * be less than the supply, which is the case for any LDO really. + * + * The best way to let the framework handle this is to set the + * min_dropout_uV field. However the AXP318 documentation + * does not provide any information about this. + * + * Realistically, it can't be less than 1uV so use this + * for all LDOs until we know more. + */ +#define AXP318_LDO_MIN_DROPOUT 1 /* uV */ + + #define AXP717_DCDC1_NUM_VOLTAGES 88 #define AXP717_DCDC2_NUM_VOLTAGES 107 #define AXP717_DCDC3_NUM_VOLTAGES 103 @@ -371,8 +395,8 @@ .ops = &axp20x_ops, \ } -#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ - _vmask, _ereg, _emask) \ +#define AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _ops, _bpreg, _bpmask, _dropout) \ [_family##_##_id] = { \ .name = (_match), \ .supply_name = (_supply), \ @@ -384,13 +408,32 @@ .owner = THIS_MODULE, \ .min_uV = (_min) * 1000, \ .uV_step = (_step) * 1000, \ + .min_dropout_uV = (_dropout), \ .vsel_reg = (_vreg), \ .vsel_mask = (_vmask), \ .enable_reg = (_ereg), \ .enable_mask = (_emask), \ - .ops = &axp20x_ops, \ + .bypass_reg = (_bpreg), \ + .bypass_mask = (_bpmask), \ + .ops = (_ops), \ } +#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask) \ + AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, &axp20x_ops, 0, 0, 0) + +#define AXP_DESC_DO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, _dropout) \ + AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, &axp20x_ops, 0, 0, _dropout) + +#define AXP_DESC_BYPASS(_family, _id, _match, _supply, _min, _max, _step, _vreg,\ + _vmask, _ereg, _emask, _bpreg, _bpmask, _dropout) \ + AXP_DESC_EXT(_family, _id, _match, _supply, _min, _max, _step, _vreg, \ + _vmask, _ereg, _emask, &axp20x_bypass_ops, _bpreg, \ + _bpmask, _dropout) + #define AXP_DESC_SW(_family, _id, _match, _supply, _ereg, _emask) \ [_family##_##_id] = { \ .name = (_match), \ @@ -419,8 +462,9 @@ .ops = &axp20x_ops_fixed \ } -#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, _n_voltages, \ - _vreg, _vmask, _ereg, _emask, _ramp_delay) \ +#define AXP_DESC_RANGES_DELAY_OPS(_family, _id, _match, _supply, _ranges, \ + _n_voltages, _vreg, _vmask, _ereg, _emask, \ + _ramp_delay, _ops) \ [_family##_##_id] = { \ .name = (_match), \ .supply_name = (_supply), \ @@ -436,10 +480,23 @@ .enable_mask = (_emask), \ .linear_ranges = (_ranges), \ .n_linear_ranges = ARRAY_SIZE(_ranges), \ - .ramp_delay = (_ramp_delay), \ - .ops = &axp20x_ops_range, \ + .ramp_delay = (_ramp_delay), \ + .ops = (_ops), \ } +#define AXP_DESC_RANGES_THRESHOLD(_family, _id, _match, _supply, _ranges, \ + _n_voltages, _vreg, _vmask, _ereg, _emask) \ + AXP_DESC_RANGES_DELAY_OPS(_family, _id, _match, _supply, _ranges, \ + _n_voltages, _vreg, _vmask, _ereg, _emask, \ + 0, &axp318_threshold_ops_range) + +#define AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \ + _n_voltages, _vreg, _vmask, _ereg, _emask, \ + _ramp_delay) \ + AXP_DESC_RANGES_DELAY_OPS(_family, _id, _match, _supply, _ranges, \ + _n_voltages, _vreg, _vmask, _ereg, _emask, \ + _ramp_delay, &axp20x_ops_range) + #define AXP_DESC_RANGES(_family, _id, _match, _supply, _ranges, _n_voltages, \ _vreg, _vmask, _ereg, _emask) \ AXP_DESC_RANGES_DELAY(_family, _id, _match, _supply, _ranges, \ @@ -567,6 +624,50 @@ static int axp20x_regulator_enable_regmap(struct regulator_dev *rdev) return regulator_enable_regmap(rdev); }; +static int axp318_threshold_check(struct regulator_dev *rdev, + unsigned int sel) +{ + int old_sel, old_uV, new_uV, enabled; + + /* Only applicable if the regulator is enabled */ + enabled = rdev->desc->ops->is_enabled(rdev); + if (enabled <= 0) + return enabled; + + old_sel = rdev->desc->ops->get_voltage_sel(rdev); + if (old_sel < 0) + return old_sel; + + old_uV = rdev->desc->ops->list_voltage(rdev, old_sel); + if (old_uV < 0) + return old_uV; + + new_uV = rdev->desc->ops->list_voltage(rdev, sel); + if (new_uV < 0) + return new_uV; + + /* Crossing the threshold ? */ + if ((old_uV <= AXP318_THRESHOLD_VOLTAGE + && new_uV > AXP318_THRESHOLD_VOLTAGE) || + (new_uV <= AXP318_THRESHOLD_VOLTAGE + && old_uV > AXP318_THRESHOLD_VOLTAGE)) + return -EBUSY; + + return 0; +} + +static int axp318_threshold_set_voltage_sel(struct regulator_dev *rdev, + unsigned int sel) +{ + int ret; + + ret = axp318_threshold_check(rdev, sel); + if (ret < 0) + return ret; + + return regulator_set_voltage_sel_regmap(rdev, sel); +} + static const struct regulator_ops axp20x_ops_fixed = { .list_voltage = regulator_list_voltage_linear, }; @@ -580,6 +681,15 @@ static const struct regulator_ops axp20x_ops_range = { .is_enabled = regulator_is_enabled_regmap, }; +static const struct regulator_ops axp318_threshold_ops_range = { + .set_voltage_sel = axp318_threshold_set_voltage_sel, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + static const struct regulator_ops axp20x_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -590,6 +700,19 @@ static const struct regulator_ops axp20x_ops = { .set_ramp_delay = axp20x_set_ramp_delay, }; +static const struct regulator_ops axp20x_bypass_ops = { + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear, + .enable = axp20x_regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_ramp_delay = axp20x_set_ramp_delay, + .get_bypass = regulator_get_bypass_regmap, + .set_bypass = regulator_set_bypass_regmap, +}; + + static const struct regulator_ops axp20x_ops_sw = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -765,6 +888,158 @@ static const struct regulator_desc axp313a_regulators[] = { AXP_DESC_FIXED(AXP313A, RTC_LDO, "rtc-ldo", "vin1", 1800), }; +static const struct linear_range axp318_dcdc2_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), + REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000), +}; + +static const struct linear_range axp318_dcdc6_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), + REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000), + REGULATOR_LINEAR_RANGE(1800000, 88, 118, 20000), + REGULATOR_LINEAR_RANGE(2440000, 119, 127, 40000), +}; + +static const struct linear_range axp318_dcdc7_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), + REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000), +}; + +static const struct linear_range axp318_dcdc8_ranges[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), + REGULATOR_LINEAR_RANGE(1220000, 71, 102, 20000), + REGULATOR_LINEAR_RANGE(1900000, 103, 118, 100000), +}; + +static const struct regulator_desc axp318_regulators[] = { + AXP_DESC(AXP318, DCDC1, "dcdc1", "vin19", 1000, 3400, 100, + AXP318_DCDC1_CONTROL, AXP318_DCDC1_V_OUT_MASK, + AXP318_DCDC_OUTPUT_CONTROL1, BIT(0)), + AXP_DESC_RANGES(AXP318, DCDC2, "dcdc2", "vin23", + axp318_dcdc2_ranges, 88, + AXP318_DCDC2_CONTROL, AXP318_DCDC2_V_OUT_MASK, + AXP318_DCDC_OUTPUT_CONTROL1, BIT(1)), + AXP_DESC_RANGES(AXP318, DCDC3, "dcdc3", "vin23", + axp318_dcdc2_ranges, 88, + AXP318_DCDC3_CONTROL, AXP318_DCDC2_V_OUT_MASK, + AXP318_DCDC_OUTPUT_CONTROL1, BIT(2)), + AXP_DESC_RANGES(AXP318, DCDC4, "dcdc4", "vin45", + axp318_dcdc2_ranges, 88, + AXP318_DCDC4_CONTROL, AXP318_DCDC2_V_OUT_MASK, + AXP318_DCDC_OUTPUT_CONTROL1, BIT(3)), + AXP_DESC_RANGES(AXP318, DCDC5, "dcdc5", "vin45", + axp318_dcdc2_ranges, 88, + AXP318_DCDC5_CONTROL, AXP318_DCDC2_V_OUT_MASK, + AXP318_DCDC_OUTPUT_CONTROL1, BIT(4)), + AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC6, "dcdc6", "vin678", + axp318_dcdc6_ranges, 128, + AXP318_DCDC6_CONTROL, AXP318_DCDC2_V_OUT_MASK, + AXP318_DCDC_OUTPUT_CONTROL1, BIT(5)), + AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC7, "dcdc7", "vin678", + axp318_dcdc7_ranges, 103, + AXP318_DCDC7_CONTROL, AXP318_DCDC2_V_OUT_MASK, + AXP318_DCDC_OUTPUT_CONTROL1, BIT(6)), + AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC8, "dcdc8", "vin678", + axp318_dcdc8_ranges, 119, + AXP318_DCDC8_CONTROL, AXP318_DCDC2_V_OUT_MASK, + AXP318_DCDC_OUTPUT_CONTROL1, BIT(7)), + AXP_DESC_RANGES_THRESHOLD(AXP318, DCDC9, "dcdc9", "vin19", + axp318_dcdc8_ranges, 119, + AXP318_DCDC9_CONTROL, AXP318_DCDC2_V_OUT_MASK, + AXP318_DCDC_OUTPUT_CONTROL2, BIT(0)), + AXP_DESC_SW(AXP318, SWOUT1, "swout1", NULL, + AXP318_DCDC_OUTPUT_CONTROL2, BIT(3)), + AXP_DESC_SW(AXP318, SWOUT2, "swout2", NULL, + AXP318_DCDC_OUTPUT_CONTROL2, BIT(4)), + AXP_DESC_DO(AXP318, ALDO1, "aldo1", "aldo156in", 500, 3400, 100, + AXP318_ALDO1_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL1, BIT(0), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, ALDO2, "aldo2", "aldo234in", 500, 3400, 100, + AXP318_ALDO2_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL1, BIT(1), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, ALDO3, "aldo3", "aldo234in", 500, 3400, 100, + AXP318_ALDO3_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL1, BIT(2), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, ALDO4, "aldo4", "aldo234in", 500, 3400, 100, + AXP318_ALDO4_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL1, BIT(3), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, ALDO5, "aldo5", "aldo156in", 500, 3400, 100, + AXP318_ALDO5_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL1, BIT(4), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, ALDO6, "aldo6", "aldo156in", 500, 3400, 100, + AXP318_ALDO6_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL1, BIT(5), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, BLDO1, "bldo1", "bldoin", 500, 3400, 100, + AXP318_BLDO1_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL1, BIT(6), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, BLDO2, "bldo2", "bldoin", 500, 3400, 100, + AXP318_BLDO2_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL1, BIT(7), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, BLDO3, "bldo3", "bldoin", 500, 3400, 100, + AXP318_BLDO3_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL2, BIT(0), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, BLDO4, "bldo4", "bldoin", 500, 3400, 100, + AXP318_BLDO4_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL2, BIT(1), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, BLDO5, "bldo5", "bldoin", 500, 3400, 100, + AXP318_BLDO5_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL2, BIT(2), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, CLDO1, "cldo1", "cldoin", 500, 3400, 100, + AXP318_CLDO1_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL2, BIT(3), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, CLDO2, "cldo2", "cldoin", 500, 3400, 100, + AXP318_CLDO2_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL2, BIT(4), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, CLDO3, "cldo3", "cldoin", 500, 3400, 100, + AXP318_CLDO3_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL2, BIT(5), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, CLDO4, "cldo4", "cldoin", 500, 3400, 100, + AXP318_CLDO4_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL2, BIT(6), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, CLDO5, "cldo5", "cldoin", 500, 3400, 100, + AXP318_CLDO5_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL2, BIT(7), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, DLDO1, "dldo1", "dldoin", 500, 3400, 100, + AXP318_DLDO1_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL3, BIT(0), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, DLDO2, "dldo2", "dldoin", 500, 3400, 100, + AXP318_DLDO2_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL3, BIT(1), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, DLDO3, "dldo3", "dldoin", 500, 3400, 100, + AXP318_DLDO3_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL3, BIT(2), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, DLDO4, "dldo4", "dldoin", 500, 3400, 100, + AXP318_DLDO4_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL3, BIT(3), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, DLDO5, "dldo5", "dldoin", 500, 3400, 100, + AXP318_DLDO5_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL3, BIT(4), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, DLDO6, "dldo6", "dldoin", 500, 3400, 100, + AXP318_DLDO6_CONTROL, AXP318_LDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL3, BIT(5), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, ELDO1, "eldo1", "eldoin", 500, 1500, 25, + AXP318_ELDO1_CONTROL, AXP318_ELDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL3, BIT(6), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, ELDO2, "eldo2", "eldoin", 500, 1500, 25, + AXP318_ELDO2_CONTROL, AXP318_ELDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL3, BIT(7), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, ELDO3, "eldo3", "eldoin", 500, 1500, 25, + AXP318_ELDO3_CONTROL, AXP318_ELDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL4, BIT(0), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_BYPASS(AXP318, ELDO4, "eldo4", "eldoin", 500, 1500, 25, + AXP318_ELDO4_CONTROL, AXP318_ELDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL4, BIT(1), + AXP318_ELDO4_CONTROL, BIT(6), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_BYPASS(AXP318, ELDO5, "eldo5", "eldoin", 500, 1500, 25, + AXP318_ELDO5_CONTROL, AXP318_ELDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL4, BIT(2), + AXP318_ELDO5_CONTROL, BIT(6), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_DO(AXP318, ELDO6, "eldo6", "eldoin", 500, 1500, 25, + AXP318_ELDO6_CONTROL, AXP318_ELDO_V_OUT_MASK, + AXP318_LDO_OUTPUT_CONTROL4, BIT(3), AXP318_LDO_MIN_DROPOUT), + AXP_DESC_FIXED(AXP318, RTC_LDO, "rtc-ldo", "ips", 1800), +}; + static const struct linear_range axp717_dcdc1_ranges[] = { REGULATOR_LINEAR_RANGE(500000, 0, 70, 10000), REGULATOR_LINEAR_RANGE(1220000, 71, 87, 20000), @@ -1347,6 +1622,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq) step = 150; break; case AXP313A_ID: + case AXP318_ID: case AXP323_ID: case AXP717_ID: case AXP15060_ID: @@ -1430,6 +1706,20 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work workmode <<= ffs(mask) - 1; break; + case AXP318_ID: + /* + * Only DCDC1 has PWM control on the AXP318 + * The other DCDCs control DVM through bit 7 of the related + * registers. Work mode could possibly extended to deal with + * this but it is not how it is documented at the moment + */ + if (id != AXP318_DCDC1) + return -EINVAL; + reg = AXP318_DCDC1_CONTROL; + mask = AXP318_DCDC1_PFM_PWM_CTRL; + workmode <<= ffs(mask) - 1; + break; + case AXP806_ID: /* * AXP806 DCDC regulator IDs have the same range as AXP22X. @@ -1543,6 +1833,17 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) } break; + case AXP318_ID: + regmap_read(axp20x->regmap, AXP318_DCDC_CONTROL1, ®); + + switch (id) { + case AXP318_DCDC3: + return !!(reg & AXP318_DCDC23_POLYPHASE_CTRL); + case AXP318_DCDC5: + return !!(reg & AXP318_DCDC45_POLYPHASE_CTRL); + } + break; + default: return false; } @@ -1585,6 +1886,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev) regulators = axp313a_regulators; nregulators = AXP313A_REG_ID_MAX; break; + case AXP318_ID: + regulators = axp318_regulators; + nregulators = AXP318_REG_ID_MAX; + break; case AXP717_ID: regulators = axp717_regulators; nregulators = AXP717_REG_ID_MAX; @@ -1651,7 +1956,9 @@ static int axp20x_regulator_probe(struct platform_device *pdev) if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) || (regulators == axp803_regulators && i == AXP803_DC1SW) || (regulators == axp809_regulators && i == AXP809_DC1SW) || - (regulators == axp15060_regulators && i == AXP15060_SW)) { + (regulators == axp15060_regulators && i == AXP15060_SW) || + (regulators == axp318_regulators && i == AXP318_SWOUT1) || + (regulators == axp318_regulators && i == AXP318_SWOUT2)) { new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL); if (!new_desc) @@ -1709,7 +2016,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev) */ if ((regulators == axp22x_regulators && i == AXP22X_DCDC1) || (regulators == axp809_regulators && i == AXP809_DCDC1) || - (regulators == axp15060_regulators && i == AXP15060_DCDC1)) + (regulators == axp15060_regulators && i == AXP15060_DCDC1) || + (regulators == axp318_regulators && i == AXP318_DCDC1)) of_property_read_string(rdev->dev.of_node, "regulator-name", &dcdc1_name); diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index c1f9dc06387a..10a959f362d3 100644 --- a/include/linux/mfd/axp20x.h +++ b/include/linux/mfd/axp20x.h @@ -128,6 +128,7 @@ enum axp20x_variants { #define AXP318_DCDC7_CONTROL 0x18 #define AXP318_DCDC8_CONTROL 0x19 #define AXP318_DCDC9_CONTROL 0x1a +#define AXP318_DCDC_CONTROL1 0x1b #define AXP318_LDO_OUTPUT_CONTROL1 0x20 #define AXP318_LDO_OUTPUT_CONTROL2 0x21 #define AXP318_LDO_OUTPUT_CONTROL3 0x22 @@ -562,6 +563,50 @@ enum { AXP313A_REG_ID_MAX, }; +enum { + AXP318_DCDC1 = 0, + AXP318_DCDC2, + AXP318_DCDC3, + AXP318_DCDC4, + AXP318_DCDC5, + AXP318_DCDC6, + AXP318_DCDC7, + AXP318_DCDC8, + AXP318_DCDC9, + AXP318_ALDO1, + AXP318_ALDO2, + AXP318_ALDO3, + AXP318_ALDO4, + AXP318_ALDO5, + AXP318_ALDO6, + AXP318_BLDO1, + AXP318_BLDO2, + AXP318_BLDO3, + AXP318_BLDO4, + AXP318_BLDO5, + AXP318_CLDO1, + AXP318_CLDO2, + AXP318_CLDO3, + AXP318_CLDO4, + AXP318_CLDO5, + AXP318_DLDO1, + AXP318_DLDO2, + AXP318_DLDO3, + AXP318_DLDO4, + AXP318_DLDO5, + AXP318_DLDO6, + AXP318_ELDO1, + AXP318_ELDO2, + AXP318_ELDO3, + AXP318_ELDO4, + AXP318_ELDO5, + AXP318_ELDO6, + AXP318_SWOUT1, + AXP318_SWOUT2, + AXP318_RTC_LDO, + AXP318_REG_ID_MAX, +}; + enum { AXP717_DCDC1 = 0, AXP717_DCDC2, -- 2.47.3