From: Constantine Shulyupin <const@xxxxxxxxxxxxx> Introduced nct7802_platform_data, nct7802_parse_dt, nct7802_platform_data_set. Parsing of DT nodes - compatible = "nuvoton,nct7802-sensor", with "sensor-type" = "thermal-diode" | "thermistor" | "voltage" | "local" | "vcc" | "vcore" - compatible = "nuvoton,nct7802-fan", with boolen properties "direct-current", "invert", "invert" - compatible = "nuvoton,nct7802-peci" Signed-off-by: Constantine Shulyupin <const@xxxxxxxxxxxxx> --- Changed in v3: - Removed nuvoton,sensorX-type - Introduced nct7802_platform_data, new DT parser for sensors, fans, peci, vcc, vcore Changed in v2: - removed tempX_type - introduced nuvoton,sensorX-type with string values Changed in v1: - Introduced tempX_type with numerical values --- drivers/hwmon/nct7802.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c index 3ce33d2..dee9eb3 100644 --- a/drivers/hwmon/nct7802.c +++ b/drivers/hwmon/nct7802.c @@ -53,6 +53,8 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = { #define REG_PECI_ENABLE 0x23 #define REG_FAN_ENABLE 0x24 #define REG_VMON_ENABLE 0x25 +#define REG_FAN_TYPE 0x5e +#define REG_FAN_MODE 0x5f #define REG_PWM(x) (0x60 + (x)) #define REG_SMARTFAN_EN(x) (0x64 + (x) / 2) #define SMARTFAN_EN_SHIFT(x) ((x) % 2 * 4) @@ -69,6 +71,18 @@ struct nct7802_data { struct mutex access_lock; /* for multi-byte read and write operations */ }; +struct nct7802_platform_data { + s8 sensor_type[3]; + s8 local_temp_enable; + s8 vcc_enable; + s8 vcore_enable; + s8 fan_enable[3]; + s8 fan_dc[2]; /* direct current instead PWM */ + s8 fan_od[3]; /* open drain */ + s8 fan_inv[3]; /* inverted polarity */ + s8 peci_enable[2]; +}; + static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1077,6 +1091,151 @@ static const struct regmap_config nct7802_regmap_config = { .volatile_reg = nct7802_regmap_is_volatile, }; +static int nct7802_parse_dt(struct device_node *node, + struct nct7802_platform_data *pdata) +{ + struct device_node *child; + const char *sen_type; + int ret; + int i; + + for_each_child_of_node(node, child) { + u32 reg = 0xFF; + + of_property_read_u32(child, "reg", ®); + if (of_device_is_compatible(child, "nuvoton,nct7802-sensor")) { + ret = of_property_read_string(child, + "sensor-type", &sen_type); + if (ret < 0) { + pr_err("%s: expected property sensor-type\n", + child->full_name); + return -EINVAL; + } + if (!strcmp(sen_type, "local")) { + pdata->local_temp_enable = 1; + continue; + } else if (!strcmp(sen_type, "vcc")) { + pdata->vcc_enable = 1; + continue; + } else if (!strcmp(sen_type, "vcore")) { + pdata->vcore_enable = 1; + continue; + } + if (reg >= ARRAY_SIZE(pdata->sensor_type)) { + pr_err("%s: invalid value: reg=%d\n", + child->full_name, reg); + return -EINVAL; + } + if (!strcmp(sen_type, "thermal-diode")) { + pdata->sensor_type[reg] = 1; + } else if (!strcmp(sen_type, "thermistor")) { + pdata->sensor_type[reg] = 2; + } else if (!strcmp(sen_type, "voltage")) { + pdata->sensor_type[reg] = 3; + } else { + pr_err("%s: invalid sensor-type=\"%s\"\n", + child->full_name, sen_type); + return -EINVAL; + } + } else if (of_device_is_compatible(child, + "nuvoton,nct7802-fan")) { + if (reg >= ARRAY_SIZE(pdata->fan_enable)) { + pr_err("%s: invalid value: %s=%d\n", + child->full_name, "reg", reg); + return -EINVAL; + } + pdata->fan_enable[reg] = 1; + if (of_property_read_bool(child, "direct-current")) { + if (reg >= ARRAY_SIZE(pdata->fan_dc)) { + pr_err("%s: invalid value: %s=%d\n", + child->full_name, "reg", reg); + return -EINVAL; + } + pdata->fan_dc[reg] = 1; + } + pdata->fan_od[reg] = + of_property_read_bool(child, "open-drain"); + pdata->fan_inv[reg] = + of_property_read_bool(child, "invert"); + } else if (of_device_is_compatible(child, + "nuvoton,nct7802-peci")) { + if (reg >= ARRAY_SIZE(pdata->peci_enable)) { + pr_err("%s: invalid value: reg=%d\n", + child->full_name, reg); + return -EINVAL; + } + pdata->peci_enable[reg] = 1; + } + } + + return 0; +} + +static int nct7802_platform_data_set(struct nct7802_data *data, + struct nct7802_platform_data *pdata) +{ + int ret; + int i; + + /* Enable ADC */ + ret = regmap_update_bits(data->regmap, REG_START, 1, 1); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(pdata->sensor_type); i++) { + ret = regmap_update_bits(data->regmap, REG_MODE, + 3 << 2 * i, + pdata->sensor_type[i] << 2 * i); + if (ret) + return ret; + } + ret = regmap_update_bits(data->regmap, REG_MODE, + 1 << 6, + pdata->local_temp_enable << 6); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(pdata->fan_enable); i++) { + ret = regmap_update_bits(data->regmap, REG_FAN_ENABLE, + 1 << i, pdata->fan_enable[i] << i); + } + for (i = 0; i < ARRAY_SIZE(pdata->peci_enable); i++) { + ret = regmap_update_bits(data->regmap, REG_PECI_ENABLE, + 1 << i, pdata->peci_enable[i] << i); + if (ret) + return ret; + } + ret = regmap_update_bits(data->regmap, REG_VMON_ENABLE, 1, + pdata->vcc_enable); + if (ret) + return ret; + + ret = regmap_update_bits(data->regmap, REG_VMON_ENABLE, 1 << 1, + pdata->vcore_enable << 1); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(pdata->fan_dc); i++) { + ret = regmap_update_bits(data->regmap, REG_FAN_TYPE, 1 << i, + pdata->fan_dc[i] << i); + if (ret) + return ret; + } + for (i = 0; i < ARRAY_SIZE(pdata->fan_od); i++) { + ret = regmap_update_bits(data->regmap, REG_FAN_MODE, 1 << i, + pdata->fan_od[i] << i); + if (ret) + return ret; + } + for (i = 0; i < ARRAY_SIZE(pdata->fan_inv); i++) { + ret = regmap_update_bits(data->regmap, REG_FAN_MODE, + 1 << (i + 4), + pdata->fan_inv[i] << (i + 4)); + if (ret) + return ret; + } + return 0; +} + static int nct7802_init_chip(struct nct7802_data *data) { int err; @@ -1098,11 +1257,27 @@ static int nct7802_init_chip(struct nct7802_data *data) static int nct7802_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct nct7802_platform_data *pdata; struct device *dev = &client->dev; struct nct7802_data *data; struct device *hwmon_dev; int ret; + pdata = dev_get_platdata(dev); +#ifdef CONFIG_OF + if (dev->of_node) { + pdata = devm_kzalloc(dev, sizeof(struct nct7802_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + ret = nct7802_parse_dt(dev->of_node, pdata); + if (ret < 0) { + devm_kfree(dev, pdata); + return ret; + } + } +#endif + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -1113,7 +1288,10 @@ static int nct7802_probe(struct i2c_client *client, mutex_init(&data->access_lock); - ret = nct7802_init_chip(data); + if (pdata) + ret = nct7802_platform_data_set(data, pdata); + else + ret = nct7802_init_chip(data); if (ret < 0) return ret; @@ -1133,10 +1311,16 @@ static const struct i2c_device_id nct7802_idtable[] = { }; MODULE_DEVICE_TABLE(i2c, nct7802_idtable); +static const struct __maybe_unused of_device_id nct7802_dt_match[] = { + { .compatible = "nuvoton,nct7802" }, + { }, +}; + static struct i2c_driver nct7802_driver = { .class = I2C_CLASS_HWMON, .driver = { .name = DRVNAME, + .of_match_table = of_match_ptr(nct7802_dt_match), }, .detect = nct7802_detect, .probe = nct7802_probe, -- 1.9.1 _______________________________________________ lm-sensors mailing list lm-sensors@xxxxxxxxxxxxxx http://lists.lm-sensors.org/mailman/listinfo/lm-sensors