123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include <linux/delay.h>
- #include <linux/i2c.h>
- #include <linux/module.h>
- #include <linux/of_gpio.h>
- #include <linux/regulator/consumer.h>
- #include <linux/thermal.h>
- #define MAX31760_CTRL_REG1 0x00
- #define MAX31760_CTRL_REG2 0x01
- #define MAX31760_CTRL_REG3 0x02
- #define MAX31760_DUTY_CYCLE_CTRL_REG 0x50
- #define MAX31760_TC1H_REG 0x52
- #define MAX31760_TC1L_REG 0x53
- #define MAX31760_TC2H_REG 0x54
- #define MAX31760_TC2L_REG 0x55
- #define VDD_MAX_UV 3300000
- #define VDD_MIN_UV 3296000
- #define VDD_LOAD_UA 300000
- #define VCCA_MAX_UV 1800000
- #define VCCA_MIN_UV 1800000
- #define VCCA_LOAD_UA 600000
- #define FAN_SPEED_LEVEL0 0
- #define FAN_SPEED_MAX 100
- #define SPEED_CAL_CONST (60 * 100000)
- #define MSB_CONVERT_DEC (256)
- #define PWM_FACTOR 39
- struct max31760_data {
- struct device *dev;
- struct i2c_client *i2c_client;
- struct thermal_cooling_device *cdev;
- struct mutex update_lock;
- struct regulator *vdd_reg;
- struct regulator *vcca_reg;
- u32 fan_num;
- u32 pwr_en_gpio;
- unsigned int cur_state;
- atomic_t in_suspend;
- };
- static int max31760_read_byte(struct max31760_data *pdata, u8 reg, u8 *val)
- {
- int ret;
- struct i2c_client *client = pdata->i2c_client;
- ret = i2c_smbus_read_byte_data(client, reg);
- if (ret < 0)
- dev_err(pdata->dev, "failed read reg 0x%02x failure, ret:%d\n", reg, ret);
- *val = (u8)ret;
- dev_dbg(pdata->dev, "success read reg 0x%x=0x%x\n", reg, *val);
- return ret;
- }
- static int max31760_write_byte(struct max31760_data *pdata, u8 reg, u8 val)
- {
- int ret = 0;
- struct i2c_client *client = pdata->i2c_client;
- ret = i2c_smbus_write_byte_data(client, reg, val);
- if (ret < 0) {
- dev_err(pdata->dev, "failed write reg %#x failure, ret:%d\n", reg, ret);
- return ret;
- }
- dev_dbg(pdata->dev, "successfully write reg %#x=%#x\n", reg, val);
- return 0;
- }
- static void max31760_enable_gpio(struct max31760_data *pdata, int on)
- {
- gpio_direction_output(pdata->pwr_en_gpio, on);
- dev_dbg(pdata->dev, "max31760 gpio:%d set to %d\n", pdata->pwr_en_gpio, on);
- usleep_range(20000, 20100);
- }
- static void max31760_speed_control(struct max31760_data *pdata, unsigned long level)
- {
- unsigned long data;
- data = level * 255 / 100;
- max31760_write_byte(pdata, MAX31760_DUTY_CYCLE_CTRL_REG, data);
- }
- static void max31760_set_cur_state_common(struct max31760_data *pdata,
- unsigned long state)
- {
- if (!atomic_read(&pdata->in_suspend))
- max31760_speed_control(pdata, state);
- pdata->cur_state = state;
- }
- static int max31760_get_max_state(struct thermal_cooling_device *cdev,
- unsigned long *state)
- {
- *state = FAN_SPEED_MAX;
- return 0;
- }
- static int max31760_get_cur_state(struct thermal_cooling_device *cdev,
- unsigned long *state)
- {
- struct max31760_data *data = cdev->devdata;
- mutex_lock(&data->update_lock);
- *state = data->cur_state;
- mutex_unlock(&data->update_lock);
- return 0;
- }
- static int max31760_set_cur_state(struct thermal_cooling_device *cdev,
- unsigned long state)
- {
- struct max31760_data *data = cdev->devdata;
- if (state > FAN_SPEED_MAX) {
- dev_err(data->dev, "fail to set current state\n");
- return -EINVAL;
- }
- mutex_lock(&data->update_lock);
- max31760_set_cur_state_common(data, state);
- mutex_unlock(&data->update_lock);
- return 0;
- }
- static struct thermal_cooling_device_ops max31760_cooling_ops = {
- .get_max_state = max31760_get_max_state,
- .get_cur_state = max31760_get_cur_state,
- .set_cur_state = max31760_set_cur_state,
- };
- static ssize_t speed_control_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct max31760_data *data = dev_get_drvdata(dev);
- int ret;
- if (!data) {
- pr_err("invalid driver pointer\n");
- return -ENODEV;
- }
- ret = scnprintf(buf, PAGE_SIZE, "%d\n", data->cur_state);
- return ret;
- }
- static ssize_t speed_control_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct max31760_data *data = dev_get_drvdata(dev);
- unsigned long value;
- if (kstrtoul(buf, 0, &value))
- return -EINVAL;
- mutex_lock(&data->update_lock);
- max31760_set_cur_state_common(data, value);
- mutex_unlock(&data->update_lock);
- return count;
- }
- static int max31760_read_speed(struct max31760_data *data,
- u8 index, u32 *speed)
- {
- u8 tch = 0, tcl = 0;
- u8 value = 0;
- int ret = 0;
- if (index == 1) {
- ret = max31760_read_byte(data, MAX31760_TC1H_REG, &value);
- if (ret < 0)
- return ret;
- tch = value;
- ret = max31760_read_byte(data, MAX31760_TC1L_REG, &value);
- if (ret < 0)
- return ret;
- tcl = value;
- } else if (index == 2) {
- ret = max31760_read_byte(data, MAX31760_TC2H_REG, &value);
- if (ret < 0)
- return ret;
- tch = value;
- ret = max31760_read_byte(data, MAX31760_TC2L_REG, &value);
- if (ret < 0)
- return ret;
- tcl = value;
- }
- *speed = SPEED_CAL_CONST / (tch * MSB_CONVERT_DEC + tcl) / 2;
- return 0;
- }
- static ssize_t speed_tc1_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct max31760_data *data = dev_get_drvdata(dev);
- u32 speed;
- int ret;
- if (!data) {
- pr_err("invalid driver pointer\n");
- return -ENODEV;
- }
- ret = max31760_read_speed(data, 1, &speed);
- if (ret < 0) {
- dev_err(data->dev, "can not read fan speed\n");
- return -EINVAL;
- }
- ret = scnprintf(buf, PAGE_SIZE, "%d\n", speed);
- dev_dbg(data->dev, "TC1 current speed is %d\n", speed);
- return ret;
- }
- static ssize_t speed_tc2_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct max31760_data *data = dev_get_drvdata(dev);
- u32 speed;
- int ret;
- if (!data) {
- pr_err("invalid driver pointer\n");
- return -ENODEV;
- }
- ret = max31760_read_speed(data, 2, &speed);
- if (ret < 0) {
- dev_err(data->dev, "can not read fan speed\n");
- return -EINVAL;
- }
- ret = scnprintf(buf, PAGE_SIZE, "%d\n", speed);
- dev_dbg(data->dev, "TC2 current speed is %d\n", speed);
- return ret;
- }
- static ssize_t pwm_duty_show(struct device *dev, struct device_attribute *attr,
- char *buf)
- {
- struct max31760_data *data = dev_get_drvdata(dev);
- u32 duty;
- u8 value = 0;
- int ret;
- if (!data) {
- pr_err("invalid driver pointer\n");
- return -ENODEV;
- }
- ret = max31760_read_byte(data, MAX31760_DUTY_CYCLE_CTRL_REG, &value);
- if (ret < 0)
- return ret;
- duty = value * PWM_FACTOR;
- ret = scnprintf(buf, PAGE_SIZE, "%d\n", duty);
- return ret;
- }
- static DEVICE_ATTR_RW(speed_control);
- static DEVICE_ATTR_RO(speed_tc1);
- static DEVICE_ATTR_RO(speed_tc2);
- static DEVICE_ATTR_RO(pwm_duty);
- static struct attribute *max31760_sysfs_attrs[] = {
- &dev_attr_speed_control.attr,
- &dev_attr_speed_tc1.attr,
- &dev_attr_speed_tc2.attr,
- &dev_attr_pwm_duty.attr,
- NULL,
- };
- static int max31760_register_cdev(struct max31760_data *pdata)
- {
- int ret = 0;
- char cdev_name[THERMAL_NAME_LENGTH] = "";
- snprintf(cdev_name, THERMAL_NAME_LENGTH, "fan-max31760");
- pdata->cdev = thermal_of_cooling_device_register(pdata->dev->of_node, cdev_name,
- pdata, &max31760_cooling_ops);
- if (IS_ERR(pdata->cdev)) {
- ret = PTR_ERR(pdata->cdev);
- dev_err(pdata->dev, "Cooling register failed for %s, ret:%d\n", cdev_name, ret);
- pdata->cdev = NULL;
- return ret;
- }
- dev_dbg(pdata->dev, "Cooling register success for %s\n", cdev_name);
- return 0;
- }
- static void max31760_hw_init(struct max31760_data *pdata)
- {
- max31760_write_byte(pdata, MAX31760_CTRL_REG1, 0x19);
- max31760_write_byte(pdata, MAX31760_CTRL_REG2, 0x11);
- if (pdata->fan_num == 1)
- max31760_write_byte(pdata, MAX31760_CTRL_REG3, 0x31);
- else if (pdata->fan_num == 2)
- max31760_write_byte(pdata, MAX31760_CTRL_REG3, 0x33);
- mutex_lock(&pdata->update_lock);
- max31760_speed_control(pdata, FAN_SPEED_LEVEL0);
- pdata->cur_state = FAN_SPEED_LEVEL0;
- mutex_unlock(&pdata->update_lock);
- atomic_set(&pdata->in_suspend, 0);
- }
- static int max31760_parse_dt(struct max31760_data *pdata)
- {
- int ret = 0;
- struct device_node *node = pdata->dev->of_node;
- if (!node) {
- pr_err("device tree info missing\n");
- return -EINVAL;
- }
- ret = of_property_read_u32(node, "maxim,fan-num", &pdata->fan_num);
- if (ret)
- pdata->fan_num = 1;
- if (pdata->fan_num > 2)
- pdata->fan_num = 2;
- pdata->pwr_en_gpio = of_get_named_gpio(node, "maxim,pwr-en-gpio", 0);
- if (!gpio_is_valid(pdata->pwr_en_gpio)) {
- dev_err(pdata->dev, "enable gpio not specified\n");
- return -EINVAL;
- }
- ret = gpio_request(pdata->pwr_en_gpio, "pwr_en_gpio");
- if (ret) {
- pr_err("enable gpio request failed, ret:%d\n", ret);
- goto error;
- }
- max31760_enable_gpio(pdata, 1);
- return ret;
- error:
- gpio_free(pdata->pwr_en_gpio);
- return ret;
- }
- static struct attribute_group max31760_attribute_group = {
- .attrs = max31760_sysfs_attrs,
- };
- static int max31760_enable_vregs(struct max31760_data *pdata)
- {
- int ret = 0;
- pdata->vdd_reg = devm_regulator_get(pdata->dev, "maxim,vdd");
- if (IS_ERR(pdata->vdd_reg)) {
- ret = PTR_ERR(pdata->vdd_reg);
- dev_err(pdata->dev, "couldn't get vdd_reg regulator, ret:%d\n", ret);
- pdata->vdd_reg = NULL;
- return ret;
- }
- regulator_set_voltage(pdata->vdd_reg, VDD_MIN_UV, VDD_MAX_UV);
- regulator_set_load(pdata->vdd_reg, VDD_LOAD_UA);
- ret = regulator_enable(pdata->vdd_reg);
- if (ret < 0) {
- dev_err(pdata->dev, "vdd_reg regulator failed, ret:%d\n", ret);
- regulator_set_voltage(pdata->vdd_reg, 0, VDD_MAX_UV);
- regulator_set_load(pdata->vdd_reg, 0);
- return -EINVAL;
- }
- pdata->vcca_reg = devm_regulator_get(pdata->dev, "maxim,vcca");
- if (IS_ERR(pdata->vcca_reg)) {
- ret = PTR_ERR(pdata->vcca_reg);
- dev_err(pdata->dev, "couldn't get vcca_reg regulator, ret:%d\n", ret);
- pdata->vcca_reg = NULL;
- return ret;
- }
- regulator_set_voltage(pdata->vcca_reg, VCCA_MIN_UV, VCCA_MAX_UV);
- regulator_set_load(pdata->vcca_reg, VCCA_LOAD_UA);
- ret = regulator_enable(pdata->vcca_reg);
- if (ret < 0) {
- dev_err(pdata->dev, "vcca_reg regulator failed, ret:%d\n", ret);
- regulator_set_voltage(pdata->vcca_reg, 0, VCCA_MAX_UV);
- regulator_set_load(pdata->vcca_reg, 0);
- return -EINVAL;
- }
- return 0;
- }
- static void max31760_remove(struct i2c_client *client)
- {
- struct max31760_data *pdata = i2c_get_clientdata(client);
- if (!pdata)
- return;
- thermal_cooling_device_unregister(pdata->cdev);
- regulator_disable(pdata->vdd_reg);
- regulator_disable(pdata->vcca_reg);
- max31760_enable_gpio(pdata, 0);
- gpio_free(pdata->pwr_en_gpio);
- }
- static int max31760_probe(struct i2c_client *client, const struct i2c_device_id *id)
- {
- int ret = 0;
- struct max31760_data *pdata;
- if (!client || !client->dev.of_node) {
- pr_err("max31760 invalid input\n");
- return -EINVAL;
- }
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(&client->dev, "device doesn't support I2C\n");
- return -ENODEV;
- }
- pdata = devm_kzalloc(&client->dev, sizeof(struct max31760_data), GFP_KERNEL);
- if (!pdata)
- return -ENOMEM;
- pdata->dev = &client->dev;
- pdata->i2c_client = client;
- i2c_set_clientdata(client, pdata);
- dev_set_drvdata(&client->dev, pdata);
- mutex_init(&pdata->update_lock);
- ret = max31760_parse_dt(pdata);
- if (ret) {
- dev_err(pdata->dev, "failed to parse device tree, ret:%d\n", ret);
- goto fail_parse_dt;
- }
- ret = max31760_enable_vregs(pdata);
- if (ret) {
- dev_err(pdata->dev, "failed to enable regulators, ret:%d\n", ret);
- goto fail_enable_vregs;
- }
- max31760_hw_init(pdata);
- ret = max31760_register_cdev(pdata);
- if (ret) {
- dev_err(pdata->dev, "failed to register cooling device, ret:%d\n", ret);
- goto fail_register_cdev;
- }
- ret = devm_device_add_group(&client->dev, &max31760_attribute_group);
- if (ret < 0) {
- dev_err(pdata->dev, "couldn't register sysfs group\n");
- return ret;
- }
- return ret;
- fail_register_cdev:
- max31760_remove(client);
- return ret;
- fail_enable_vregs:
- max31760_enable_gpio(pdata, 0);
- gpio_free(pdata->pwr_en_gpio);
- fail_parse_dt:
- i2c_set_clientdata(client, NULL);
- dev_set_drvdata(&client->dev, NULL);
- return ret;
- }
- static void max31760_shutdown(struct i2c_client *client)
- {
- max31760_remove(client);
- }
- static int max31760_suspend(struct device *dev)
- {
- struct max31760_data *pdata = dev_get_drvdata(dev);
- dev_dbg(dev, "enter suspend now\n");
- if (pdata) {
- atomic_set(&pdata->in_suspend, 1);
- mutex_lock(&pdata->update_lock);
- max31760_speed_control(pdata, FAN_SPEED_LEVEL0);
- max31760_enable_gpio(pdata, 0);
- regulator_disable(pdata->vdd_reg);
- mutex_unlock(&pdata->update_lock);
- }
- return 0;
- }
- static int max31760_resume(struct device *dev)
- {
- struct max31760_data *pdata = dev_get_drvdata(dev);
- int ret;
- dev_dbg(dev, "enter resume now\n");
- if (pdata) {
- atomic_set(&pdata->in_suspend, 0);
- mutex_lock(&pdata->update_lock);
- max31760_enable_gpio(pdata, 1);
- ret = regulator_enable(pdata->vdd_reg);
- if (ret < 0)
- dev_err(pdata->dev, "vdd_reg regulator failed, ret:%d\n", ret);
- max31760_write_byte(pdata, MAX31760_CTRL_REG1, 0x19);
- max31760_write_byte(pdata, MAX31760_CTRL_REG2, 0x11);
- if (pdata->fan_num == 1)
- max31760_write_byte(pdata, MAX31760_CTRL_REG3, 0x31);
- else if (pdata->fan_num == 2)
- max31760_write_byte(pdata, MAX31760_CTRL_REG3, 0x33);
- max31760_set_cur_state_common(pdata, pdata->cur_state);
- mutex_unlock(&pdata->update_lock);
- }
- return 0;
- }
- static const struct of_device_id max31760_id_table[] = {
- { .compatible = "maxim,max31760",},
- { },
- };
- static const struct i2c_device_id max31760_i2c_table[] = {
- { "max31760", 0 },
- { },
- };
- static SIMPLE_DEV_PM_OPS(max31760_pm_ops, max31760_suspend, max31760_resume);
- static struct i2c_driver max31760_i2c_driver = {
- .probe = max31760_probe,
- .remove = max31760_remove,
- .shutdown = max31760_shutdown,
- .driver = {
- .name = "max31760",
- .of_match_table = max31760_id_table,
- .pm = &max31760_pm_ops,
- },
- .id_table = max31760_i2c_table,
- };
- module_i2c_driver(max31760_i2c_driver);
- MODULE_DEVICE_TABLE(i2c, max31760_i2c_table);
- MODULE_DESCRIPTION("Maxim 31760 Fan Controller");
- MODULE_LICENSE("GPL");
|