18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// max77826-regulator.c  - regulator driver for Maxim MAX77826
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Author: Iskren Chernev <iskren.chernev@gmail.com>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/err.h>
118c2ecf20Sopenharmony_ci#include <linux/of.h>
128c2ecf20Sopenharmony_ci#include <linux/of_device.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h>
158c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h>
168c2ecf20Sopenharmony_ci#include <linux/i2c.h>
178c2ecf20Sopenharmony_ci#include <linux/regmap.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cienum max77826_registers {
208c2ecf20Sopenharmony_ci	MAX77826_REG_INT_SRC = 0x00,
218c2ecf20Sopenharmony_ci	MAX77826_REG_SYS_INT,
228c2ecf20Sopenharmony_ci	MAX77826_REG_INT1,
238c2ecf20Sopenharmony_ci	MAX77826_REG_INT2,
248c2ecf20Sopenharmony_ci	MAX77826_REG_BB_INT,
258c2ecf20Sopenharmony_ci	MAX77826_REG_INT_SRC_M,
268c2ecf20Sopenharmony_ci	MAX77826_REG_TOPSYS_INT_M,
278c2ecf20Sopenharmony_ci	MAX77826_REG_INT1_M,
288c2ecf20Sopenharmony_ci	MAX77826_REG_INT2_M,
298c2ecf20Sopenharmony_ci	MAX77826_REG_BB_INT_M,
308c2ecf20Sopenharmony_ci	MAX77826_REG_TOPSYS_STAT,
318c2ecf20Sopenharmony_ci	MAX77826_REG_STAT1,
328c2ecf20Sopenharmony_ci	MAX77826_REG_STAT2,
338c2ecf20Sopenharmony_ci	MAX77826_REG_BB_STAT,
348c2ecf20Sopenharmony_ci	/* 0x0E - 0x0F: Reserved */
358c2ecf20Sopenharmony_ci	MAX77826_REG_LDO_OPMD1 = 0x10,
368c2ecf20Sopenharmony_ci	MAX77826_REG_LDO_OPMD2,
378c2ecf20Sopenharmony_ci	MAX77826_REG_LDO_OPMD3,
388c2ecf20Sopenharmony_ci	MAX77826_REG_LDO_OPMD4,
398c2ecf20Sopenharmony_ci	MAX77826_REG_B_BB_OPMD,
408c2ecf20Sopenharmony_ci	/* 0x15 - 0x1F: Reserved */
418c2ecf20Sopenharmony_ci	MAX77826_REG_LDO1_CFG = 0x20,
428c2ecf20Sopenharmony_ci	MAX77826_REG_LDO2_CFG,
438c2ecf20Sopenharmony_ci	MAX77826_REG_LDO3_CFG,
448c2ecf20Sopenharmony_ci	MAX77826_REG_LDO4_CFG,
458c2ecf20Sopenharmony_ci	MAX77826_REG_LDO5_CFG,
468c2ecf20Sopenharmony_ci	MAX77826_REG_LDO6_CFG,
478c2ecf20Sopenharmony_ci	MAX77826_REG_LDO7_CFG,
488c2ecf20Sopenharmony_ci	MAX77826_REG_LDO8_CFG,
498c2ecf20Sopenharmony_ci	MAX77826_REG_LDO9_CFG,
508c2ecf20Sopenharmony_ci	MAX77826_REG_LDO10_CFG,
518c2ecf20Sopenharmony_ci	MAX77826_REG_LDO11_CFG,
528c2ecf20Sopenharmony_ci	MAX77826_REG_LDO12_CFG,
538c2ecf20Sopenharmony_ci	MAX77826_REG_LDO13_CFG,
548c2ecf20Sopenharmony_ci	MAX77826_REG_LDO14_CFG,
558c2ecf20Sopenharmony_ci	MAX77826_REG_LDO15_CFG,
568c2ecf20Sopenharmony_ci	/* 0x2F: Reserved */
578c2ecf20Sopenharmony_ci	MAX77826_REG_BUCK_CFG = 0x30,
588c2ecf20Sopenharmony_ci	MAX77826_REG_BUCK_VOUT,
598c2ecf20Sopenharmony_ci	MAX77826_REG_BB_CFG,
608c2ecf20Sopenharmony_ci	MAX77826_REG_BB_VOUT,
618c2ecf20Sopenharmony_ci	/* 0x34 - 0x3F: Reserved */
628c2ecf20Sopenharmony_ci	MAX77826_REG_BUCK_SS_FREQ = 0x40,
638c2ecf20Sopenharmony_ci	MAX77826_REG_UVLO_FALL,
648c2ecf20Sopenharmony_ci	/* 0x42 - 0xCE: Reserved */
658c2ecf20Sopenharmony_ci	MAX77826_REG_DEVICE_ID = 0xCF,
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cienum max77826_regulators {
698c2ecf20Sopenharmony_ci	MAX77826_LDO1 = 0,
708c2ecf20Sopenharmony_ci	MAX77826_LDO2,
718c2ecf20Sopenharmony_ci	MAX77826_LDO3,
728c2ecf20Sopenharmony_ci	MAX77826_LDO4,
738c2ecf20Sopenharmony_ci	MAX77826_LDO5,
748c2ecf20Sopenharmony_ci	MAX77826_LDO6,
758c2ecf20Sopenharmony_ci	MAX77826_LDO7,
768c2ecf20Sopenharmony_ci	MAX77826_LDO8,
778c2ecf20Sopenharmony_ci	MAX77826_LDO9,
788c2ecf20Sopenharmony_ci	MAX77826_LDO10,
798c2ecf20Sopenharmony_ci	MAX77826_LDO11,
808c2ecf20Sopenharmony_ci	MAX77826_LDO12,
818c2ecf20Sopenharmony_ci	MAX77826_LDO13,
828c2ecf20Sopenharmony_ci	MAX77826_LDO14,
838c2ecf20Sopenharmony_ci	MAX77826_LDO15,
848c2ecf20Sopenharmony_ci	MAX77826_BUCK,
858c2ecf20Sopenharmony_ci	MAX77826_BUCKBOOST,
868c2ecf20Sopenharmony_ci	MAX77826_MAX_REGULATORS,
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci#define MAX77826_MASK_LDO		0x7f
908c2ecf20Sopenharmony_ci#define MAX77826_MASK_BUCK		0xff
918c2ecf20Sopenharmony_ci#define MAX77826_MASK_BUCKBOOST		0x7f
928c2ecf20Sopenharmony_ci#define MAX77826_BUCK_RAMP_DELAY	12500
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/* values in mV */
958c2ecf20Sopenharmony_ci/* for LDO1-3 */
968c2ecf20Sopenharmony_ci#define MAX77826_NMOS_LDO_VOLT_MIN	600000
978c2ecf20Sopenharmony_ci#define MAX77826_NMOS_LDO_VOLT_MAX	2187500
988c2ecf20Sopenharmony_ci#define MAX77826_NMOS_LDO_VOLT_STEP	12500
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/* for LDO4-15 */
1018c2ecf20Sopenharmony_ci#define MAX77826_PMOS_LDO_VOLT_MIN	800000
1028c2ecf20Sopenharmony_ci#define MAX77826_PMOS_LDO_VOLT_MAX	3975000
1038c2ecf20Sopenharmony_ci#define MAX77826_PMOS_LDO_VOLT_STEP	25000
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* for BUCK */
1068c2ecf20Sopenharmony_ci#define MAX77826_BUCK_VOLT_MIN		500000
1078c2ecf20Sopenharmony_ci#define MAX77826_BUCK_VOLT_MAX		1800000
1088c2ecf20Sopenharmony_ci#define MAX77826_BUCK_VOLT_STEP		6250
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci/* for BUCKBOOST */
1118c2ecf20Sopenharmony_ci#define MAX77826_BUCKBOOST_VOLT_MIN	2600000
1128c2ecf20Sopenharmony_ci#define MAX77826_BUCKBOOST_VOLT_MAX	4187500
1138c2ecf20Sopenharmony_ci#define MAX77826_BUCKBOOST_VOLT_STEP	12500
1148c2ecf20Sopenharmony_ci#define MAX77826_VOLT_RANGE(_type)					\
1158c2ecf20Sopenharmony_ci	((MAX77826_ ## _type ## _VOLT_MAX -				\
1168c2ecf20Sopenharmony_ci	  MAX77826_ ## _type ## _VOLT_MIN) /				\
1178c2ecf20Sopenharmony_ci	 MAX77826_ ## _type ## _VOLT_STEP + 1)
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci#define MAX77826_LDO(_id, _type)					\
1208c2ecf20Sopenharmony_ci	[MAX77826_LDO ## _id] = {					\
1218c2ecf20Sopenharmony_ci		.id = MAX77826_LDO ## _id,				\
1228c2ecf20Sopenharmony_ci		.name = "LDO"#_id,					\
1238c2ecf20Sopenharmony_ci		.of_match = of_match_ptr("LDO"#_id),			\
1248c2ecf20Sopenharmony_ci		.regulators_node = "regulators",			\
1258c2ecf20Sopenharmony_ci		.ops = &max77826_most_ops,				\
1268c2ecf20Sopenharmony_ci		.min_uV = MAX77826_ ## _type ## _LDO_VOLT_MIN,		\
1278c2ecf20Sopenharmony_ci		.uV_step = MAX77826_ ## _type ## _LDO_VOLT_STEP,	\
1288c2ecf20Sopenharmony_ci		.n_voltages = MAX77826_VOLT_RANGE(_type ## _LDO),	\
1298c2ecf20Sopenharmony_ci		.enable_reg = MAX77826_REG_LDO_OPMD1 + (_id - 1) / 4,	\
1308c2ecf20Sopenharmony_ci		.enable_mask = BIT(((_id - 1) % 4) * 2 + 1),		\
1318c2ecf20Sopenharmony_ci		.vsel_reg = MAX77826_REG_LDO1_CFG + (_id - 1),		\
1328c2ecf20Sopenharmony_ci		.vsel_mask = MAX77826_MASK_LDO,				\
1338c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,					\
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci#define MAX77826_BUCK(_idx, _id, _ops)					\
1378c2ecf20Sopenharmony_ci	[MAX77826_ ## _id] = {						\
1388c2ecf20Sopenharmony_ci		.id = MAX77826_ ## _id,					\
1398c2ecf20Sopenharmony_ci		.name = #_id,						\
1408c2ecf20Sopenharmony_ci		.of_match = of_match_ptr(#_id),				\
1418c2ecf20Sopenharmony_ci		.regulators_node = "regulators",			\
1428c2ecf20Sopenharmony_ci		.ops = &_ops,						\
1438c2ecf20Sopenharmony_ci		.min_uV =  MAX77826_ ## _id ## _VOLT_MIN,		\
1448c2ecf20Sopenharmony_ci		.uV_step = MAX77826_ ## _id ## _VOLT_STEP,		\
1458c2ecf20Sopenharmony_ci		.n_voltages = MAX77826_VOLT_RANGE(_id),			\
1468c2ecf20Sopenharmony_ci		.enable_reg = MAX77826_REG_B_BB_OPMD,			\
1478c2ecf20Sopenharmony_ci		.enable_mask = BIT(_idx * 2 + 1),			\
1488c2ecf20Sopenharmony_ci		.vsel_reg = MAX77826_REG_BUCK_VOUT + _idx * 2,		\
1498c2ecf20Sopenharmony_ci		.vsel_mask = MAX77826_MASK_ ## _id,			\
1508c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,					\
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistruct max77826_regulator_info {
1568c2ecf20Sopenharmony_ci	struct regmap *regmap;
1578c2ecf20Sopenharmony_ci	struct regulator_desc *rdesc;
1588c2ecf20Sopenharmony_ci};
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic const struct regmap_config max77826_regmap_config = {
1618c2ecf20Sopenharmony_ci	.reg_bits = 8,
1628c2ecf20Sopenharmony_ci	.val_bits = 8,
1638c2ecf20Sopenharmony_ci	.max_register = MAX77826_REG_DEVICE_ID,
1648c2ecf20Sopenharmony_ci};
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int max77826_set_voltage_time_sel(struct regulator_dev *,
1678c2ecf20Sopenharmony_ci				unsigned int old_selector,
1688c2ecf20Sopenharmony_ci				unsigned int new_selector);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic const struct regulator_ops max77826_most_ops = {
1718c2ecf20Sopenharmony_ci	.enable			= regulator_enable_regmap,
1728c2ecf20Sopenharmony_ci	.disable		= regulator_disable_regmap,
1738c2ecf20Sopenharmony_ci	.is_enabled		= regulator_is_enabled_regmap,
1748c2ecf20Sopenharmony_ci	.list_voltage		= regulator_list_voltage_linear,
1758c2ecf20Sopenharmony_ci	.map_voltage		= regulator_map_voltage_linear,
1768c2ecf20Sopenharmony_ci	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
1778c2ecf20Sopenharmony_ci	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
1788c2ecf20Sopenharmony_ci};
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic const struct regulator_ops max77826_buck_ops = {
1818c2ecf20Sopenharmony_ci	.enable			= regulator_enable_regmap,
1828c2ecf20Sopenharmony_ci	.disable		= regulator_disable_regmap,
1838c2ecf20Sopenharmony_ci	.is_enabled		= regulator_is_enabled_regmap,
1848c2ecf20Sopenharmony_ci	.list_voltage		= regulator_list_voltage_linear,
1858c2ecf20Sopenharmony_ci	.map_voltage		= regulator_map_voltage_linear,
1868c2ecf20Sopenharmony_ci	.get_voltage_sel	= regulator_get_voltage_sel_regmap,
1878c2ecf20Sopenharmony_ci	.set_voltage_sel	= regulator_set_voltage_sel_regmap,
1888c2ecf20Sopenharmony_ci	.set_voltage_time_sel	= max77826_set_voltage_time_sel,
1898c2ecf20Sopenharmony_ci};
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic struct regulator_desc max77826_regulators_desc[] = {
1928c2ecf20Sopenharmony_ci	MAX77826_LDO(1, NMOS),
1938c2ecf20Sopenharmony_ci	MAX77826_LDO(2, NMOS),
1948c2ecf20Sopenharmony_ci	MAX77826_LDO(3, NMOS),
1958c2ecf20Sopenharmony_ci	MAX77826_LDO(4, PMOS),
1968c2ecf20Sopenharmony_ci	MAX77826_LDO(5, PMOS),
1978c2ecf20Sopenharmony_ci	MAX77826_LDO(6, PMOS),
1988c2ecf20Sopenharmony_ci	MAX77826_LDO(7, PMOS),
1998c2ecf20Sopenharmony_ci	MAX77826_LDO(8, PMOS),
2008c2ecf20Sopenharmony_ci	MAX77826_LDO(9, PMOS),
2018c2ecf20Sopenharmony_ci	MAX77826_LDO(10, PMOS),
2028c2ecf20Sopenharmony_ci	MAX77826_LDO(11, PMOS),
2038c2ecf20Sopenharmony_ci	MAX77826_LDO(12, PMOS),
2048c2ecf20Sopenharmony_ci	MAX77826_LDO(13, PMOS),
2058c2ecf20Sopenharmony_ci	MAX77826_LDO(14, PMOS),
2068c2ecf20Sopenharmony_ci	MAX77826_LDO(15, PMOS),
2078c2ecf20Sopenharmony_ci	MAX77826_BUCK(0, BUCK, max77826_buck_ops),
2088c2ecf20Sopenharmony_ci	MAX77826_BUCK(1, BUCKBOOST, max77826_most_ops),
2098c2ecf20Sopenharmony_ci};
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic int max77826_set_voltage_time_sel(struct regulator_dev *rdev,
2128c2ecf20Sopenharmony_ci				unsigned int old_selector,
2138c2ecf20Sopenharmony_ci				unsigned int new_selector)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	if (new_selector > old_selector) {
2168c2ecf20Sopenharmony_ci		return DIV_ROUND_UP(MAX77826_BUCK_VOLT_STEP *
2178c2ecf20Sopenharmony_ci				(new_selector - old_selector),
2188c2ecf20Sopenharmony_ci				MAX77826_BUCK_RAMP_DELAY);
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return 0;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic int max77826_read_device_id(struct regmap *regmap, struct device *dev)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	unsigned int device_id;
2278c2ecf20Sopenharmony_ci	int res;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	res = regmap_read(regmap, MAX77826_REG_DEVICE_ID, &device_id);
2308c2ecf20Sopenharmony_ci	if (!res)
2318c2ecf20Sopenharmony_ci		dev_dbg(dev, "DEVICE_ID: 0x%x\n", device_id);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return res;
2348c2ecf20Sopenharmony_ci}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_cistatic int max77826_i2c_probe(struct i2c_client *client)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
2398c2ecf20Sopenharmony_ci	struct max77826_regulator_info *info;
2408c2ecf20Sopenharmony_ci	struct regulator_config config = {};
2418c2ecf20Sopenharmony_ci	struct regulator_dev *rdev;
2428c2ecf20Sopenharmony_ci	struct regmap *regmap;
2438c2ecf20Sopenharmony_ci	int i;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	info = devm_kzalloc(dev, sizeof(struct max77826_regulator_info),
2468c2ecf20Sopenharmony_ci				GFP_KERNEL);
2478c2ecf20Sopenharmony_ci	if (!info)
2488c2ecf20Sopenharmony_ci		return -ENOMEM;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	info->rdesc = max77826_regulators_desc;
2518c2ecf20Sopenharmony_ci	regmap = devm_regmap_init_i2c(client, &max77826_regmap_config);
2528c2ecf20Sopenharmony_ci	if (IS_ERR(regmap)) {
2538c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to allocate regmap!\n");
2548c2ecf20Sopenharmony_ci		return PTR_ERR(regmap);
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	info->regmap = regmap;
2588c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, info);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	config.dev = dev;
2618c2ecf20Sopenharmony_ci	config.regmap = regmap;
2628c2ecf20Sopenharmony_ci	config.driver_data = info;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	for (i = 0; i < MAX77826_MAX_REGULATORS; i++) {
2658c2ecf20Sopenharmony_ci		rdev = devm_regulator_register(dev,
2668c2ecf20Sopenharmony_ci					       &max77826_regulators_desc[i],
2678c2ecf20Sopenharmony_ci					       &config);
2688c2ecf20Sopenharmony_ci		if (IS_ERR(rdev)) {
2698c2ecf20Sopenharmony_ci			dev_err(dev, "Failed to register regulator!\n");
2708c2ecf20Sopenharmony_ci			return PTR_ERR(rdev);
2718c2ecf20Sopenharmony_ci		}
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return max77826_read_device_id(regmap, dev);
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic const struct of_device_id __maybe_unused max77826_of_match[] = {
2788c2ecf20Sopenharmony_ci	{ .compatible = "maxim,max77826" },
2798c2ecf20Sopenharmony_ci	{ /* sentinel */ }
2808c2ecf20Sopenharmony_ci};
2818c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, max77826_of_match);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic const struct i2c_device_id max77826_id[] = {
2848c2ecf20Sopenharmony_ci	{ "max77826-regulator" },
2858c2ecf20Sopenharmony_ci	{ /* sentinel */ }
2868c2ecf20Sopenharmony_ci};
2878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, max77826_id);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic struct i2c_driver max77826_regulator_driver = {
2908c2ecf20Sopenharmony_ci	.driver = {
2918c2ecf20Sopenharmony_ci		.name = "max77826",
2928c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(max77826_of_match),
2938c2ecf20Sopenharmony_ci	},
2948c2ecf20Sopenharmony_ci	.probe_new = max77826_i2c_probe,
2958c2ecf20Sopenharmony_ci	.id_table = max77826_id,
2968c2ecf20Sopenharmony_ci};
2978c2ecf20Sopenharmony_cimodule_i2c_driver(max77826_regulator_driver);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ciMODULE_AUTHOR("Iskren Chernev <iskren.chernev@gmail.com>");
3008c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MAX77826 PMIC regulator driver");
3018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
302