brintos

brintos / linux-shallow public Read only

0
0
Text · 15.3 KiB · 4d39fbd Raw
624 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Hardware monitoring driver for EMC2305 fan controller4 *5 * Copyright (C) 2022 Nvidia Technologies Ltd.6 */7 8#include <linux/err.h>9#include <linux/hwmon.h>10#include <linux/i2c.h>11#include <linux/module.h>12#include <linux/platform_data/emc2305.h>13#include <linux/thermal.h>14 15#define EMC2305_REG_DRIVE_FAIL_STATUS	0x2716#define EMC2305_REG_VENDOR		0xfe17#define EMC2305_FAN_MAX			0xff18#define EMC2305_FAN_MIN			0x0019#define EMC2305_FAN_MAX_STATE		1020#define EMC2305_DEVICE			0x3421#define EMC2305_VENDOR			0x5d22#define EMC2305_REG_PRODUCT_ID		0xfd23#define EMC2305_TACH_REGS_UNUSE_BITS	324#define EMC2305_TACH_CNT_MULTIPLIER	0x0225#define EMC2305_TACH_RANGE_MIN		48026 27#define EMC2305_PWM_DUTY2STATE(duty, max_state, pwm_max) \28	DIV_ROUND_CLOSEST((duty) * (max_state), (pwm_max))29#define EMC2305_PWM_STATE2DUTY(state, max_state, pwm_max) \30	DIV_ROUND_CLOSEST((state) * (pwm_max), (max_state))31 32/*33 * Factor by equations [2] and [3] from data sheet; valid for fans where the number of edges34 * equal (poles * 2 + 1).35 */36#define EMC2305_RPM_FACTOR		393216037 38#define EMC2305_REG_FAN_DRIVE(n)	(0x30 + 0x10 * (n))39#define EMC2305_REG_FAN_MIN_DRIVE(n)	(0x38 + 0x10 * (n))40#define EMC2305_REG_FAN_TACH(n)		(0x3e + 0x10 * (n))41 42enum emc230x_product_id {43	EMC2305 = 0x34,44	EMC2303 = 0x35,45	EMC2302 = 0x36,46	EMC2301 = 0x37,47};48 49static const struct i2c_device_id emc2305_ids[] = {50	{ "emc2305" },51	{ "emc2303" },52	{ "emc2302" },53	{ "emc2301" },54	{ }55};56MODULE_DEVICE_TABLE(i2c, emc2305_ids);57 58/**59 * struct emc2305_cdev_data - device-specific cooling device state60 * @cdev: cooling device61 * @cur_state: cooling current state62 * @last_hwmon_state: last cooling state updated by hwmon subsystem63 * @last_thermal_state: last cooling state updated by thermal subsystem64 *65 * The 'last_hwmon_state' and 'last_thermal_state' fields are provided to support fan low limit66 * speed feature. The purpose of this feature is to provides ability to limit fan speed67 * according to some system wise considerations, like absence of some replaceable units (PSU or68 * line cards), high system ambient temperature, unreliable transceivers temperature sensing or69 * some other factors which indirectly impacts system's airflow70 * Fan low limit feature is supported through 'hwmon' interface: 'hwmon' 'pwm' attribute is71 * used for setting low limit for fan speed in case 'thermal' subsystem is configured in72 * kernel. In this case setting fan speed through 'hwmon' will never let the 'thermal'73 * subsystem to select a lower duty cycle than the duty cycle selected with the 'pwm'74 * attribute.75 * From other side, fan speed is to be updated in hardware through 'pwm' only in case the76 * requested fan speed is above last speed set by 'thermal' subsystem, otherwise requested fan77 * speed will be just stored with no PWM update.78 */79struct emc2305_cdev_data {80	struct thermal_cooling_device *cdev;81	unsigned int cur_state;82	unsigned long last_hwmon_state;83	unsigned long last_thermal_state;84};85 86/**87 * struct emc2305_data - device-specific data88 * @client: i2c client89 * @hwmon_dev: hwmon device90 * @max_state: maximum cooling state of the cooling device91 * @pwm_num: number of PWM channels92 * @pwm_separate: separate PWM settings for every channel93 * @pwm_min: array of minimum PWM per channel94 * @cdev_data: array of cooling devices data95 */96struct emc2305_data {97	struct i2c_client *client;98	struct device *hwmon_dev;99	u8 max_state;100	u8 pwm_num;101	bool pwm_separate;102	u8 pwm_min[EMC2305_PWM_MAX];103	struct emc2305_cdev_data cdev_data[EMC2305_PWM_MAX];104};105 106static char *emc2305_fan_name[] = {107	"emc2305_fan",108	"emc2305_fan1",109	"emc2305_fan2",110	"emc2305_fan3",111	"emc2305_fan4",112	"emc2305_fan5",113};114 115static void emc2305_unset_tz(struct device *dev);116 117static int emc2305_get_max_channel(const struct emc2305_data *data)118{119	return data->pwm_num;120}121 122static int emc2305_get_cdev_idx(struct thermal_cooling_device *cdev)123{124	struct emc2305_data *data = cdev->devdata;125	size_t len = strlen(cdev->type);126	int ret;127 128	if (len <= 0)129		return -EINVAL;130 131	/*132	 * Returns index of cooling device 0..4 in case of separate PWM setting.133	 * Zero index is used in case of one common PWM setting.134	 * If the mode is not set as pwm_separate, all PWMs are to be bound135	 * to the common thermal zone and should work at the same speed136	 * to perform cooling for the same thermal junction.137	 * Otherwise, return specific channel that will be used in bound138	 * related PWM to the thermal zone.139	 */140	if (!data->pwm_separate)141		return 0;142 143	ret = cdev->type[len - 1];144	switch (ret) {145	case '1' ... '5':146		return ret - '1';147	default:148		break;149	}150	return -EINVAL;151}152 153static int emc2305_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state)154{155	int cdev_idx;156	struct emc2305_data *data = cdev->devdata;157 158	cdev_idx = emc2305_get_cdev_idx(cdev);159	if (cdev_idx < 0)160		return cdev_idx;161 162	*state = data->cdev_data[cdev_idx].cur_state;163	return 0;164}165 166static int emc2305_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state)167{168	struct emc2305_data *data = cdev->devdata;169	*state = data->max_state;170	return 0;171}172 173static int __emc2305_set_cur_state(struct emc2305_data *data, int cdev_idx, unsigned long state)174{175	int ret;176	struct i2c_client *client = data->client;177	u8 val, i;178 179	state = max_t(unsigned long, state, data->cdev_data[cdev_idx].last_hwmon_state);180 181	val = EMC2305_PWM_STATE2DUTY(state, data->max_state, EMC2305_FAN_MAX);182 183	data->cdev_data[cdev_idx].cur_state = state;184	if (data->pwm_separate) {185		ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(cdev_idx), val);186		if (ret < 0)187			return ret;188	} else {189		/*190		 * Set the same PWM value in all channels191		 * if common PWM channel is used.192		 */193		for (i = 0; i < data->pwm_num; i++) {194			ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(i), val);195			if (ret < 0)196				return ret;197		}198	}199 200	return 0;201}202 203static int emc2305_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)204{205	int cdev_idx, ret;206	struct emc2305_data *data = cdev->devdata;207 208	if (state > data->max_state)209		return -EINVAL;210 211	cdev_idx =  emc2305_get_cdev_idx(cdev);212	if (cdev_idx < 0)213		return cdev_idx;214 215	/* Save thermal state. */216	data->cdev_data[cdev_idx].last_thermal_state = state;217	ret = __emc2305_set_cur_state(data, cdev_idx, state);218	if (ret < 0)219		return ret;220 221	return 0;222}223 224static const struct thermal_cooling_device_ops emc2305_cooling_ops = {225	.get_max_state = emc2305_get_max_state,226	.get_cur_state = emc2305_get_cur_state,227	.set_cur_state = emc2305_set_cur_state,228};229 230static int emc2305_show_fault(struct device *dev, int channel)231{232	struct emc2305_data *data = dev_get_drvdata(dev);233	struct i2c_client *client = data->client;234	int status_reg;235 236	status_reg = i2c_smbus_read_byte_data(client, EMC2305_REG_DRIVE_FAIL_STATUS);237	if (status_reg < 0)238		return status_reg;239 240	return status_reg & (1 << channel) ? 1 : 0;241}242 243static int emc2305_show_fan(struct device *dev, int channel)244{245	struct emc2305_data *data = dev_get_drvdata(dev);246	struct i2c_client *client = data->client;247	int ret;248 249	ret = i2c_smbus_read_word_swapped(client, EMC2305_REG_FAN_TACH(channel));250	if (ret <= 0)251		return ret;252 253	ret = ret >> EMC2305_TACH_REGS_UNUSE_BITS;254	ret = EMC2305_RPM_FACTOR / ret;255	if (ret <= EMC2305_TACH_RANGE_MIN)256		return 0;257 258	return ret * EMC2305_TACH_CNT_MULTIPLIER;259}260 261static int emc2305_show_pwm(struct device *dev, int channel)262{263	struct emc2305_data *data = dev_get_drvdata(dev);264	struct i2c_client *client = data->client;265 266	return i2c_smbus_read_byte_data(client, EMC2305_REG_FAN_DRIVE(channel));267}268 269static int emc2305_set_pwm(struct device *dev, long val, int channel)270{271	struct emc2305_data *data = dev_get_drvdata(dev);272	struct i2c_client *client = data->client;273	int ret;274 275	if (val < data->pwm_min[channel] || val > EMC2305_FAN_MAX)276		return -EINVAL;277 278	ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_DRIVE(channel), val);279	if (ret < 0)280		return ret;281	data->cdev_data[channel].cur_state = EMC2305_PWM_DUTY2STATE(val, data->max_state,282								    EMC2305_FAN_MAX);283	return 0;284}285 286static int emc2305_set_single_tz(struct device *dev, int idx)287{288	struct emc2305_data *data = dev_get_drvdata(dev);289	long pwm;290	int i, cdev_idx, ret;291 292	cdev_idx = (idx) ? idx - 1 : 0;293	pwm = data->pwm_min[cdev_idx];294 295	data->cdev_data[cdev_idx].cdev =296		thermal_cooling_device_register(emc2305_fan_name[idx], data,297						&emc2305_cooling_ops);298 299	if (IS_ERR(data->cdev_data[cdev_idx].cdev)) {300		dev_err(dev, "Failed to register cooling device %s\n", emc2305_fan_name[idx]);301		return PTR_ERR(data->cdev_data[cdev_idx].cdev);302	}303	/* Set minimal PWM speed. */304	if (data->pwm_separate) {305		ret = emc2305_set_pwm(dev, pwm, cdev_idx);306		if (ret < 0)307			return ret;308	} else {309		for (i = 0; i < data->pwm_num; i++) {310			ret = emc2305_set_pwm(dev, pwm, i);311			if (ret < 0)312				return ret;313		}314	}315	data->cdev_data[cdev_idx].cur_state =316		EMC2305_PWM_DUTY2STATE(data->pwm_min[cdev_idx], data->max_state,317				       EMC2305_FAN_MAX);318	data->cdev_data[cdev_idx].last_hwmon_state =319		EMC2305_PWM_DUTY2STATE(data->pwm_min[cdev_idx], data->max_state,320				       EMC2305_FAN_MAX);321	return 0;322}323 324static int emc2305_set_tz(struct device *dev)325{326	struct emc2305_data *data = dev_get_drvdata(dev);327	int i, ret;328 329	if (!data->pwm_separate)330		return emc2305_set_single_tz(dev, 0);331 332	for (i = 0; i < data->pwm_num; i++) {333		ret = emc2305_set_single_tz(dev, i + 1);334		if (ret)335			goto thermal_cooling_device_register_fail;336	}337	return 0;338 339thermal_cooling_device_register_fail:340	emc2305_unset_tz(dev);341	return ret;342}343 344static void emc2305_unset_tz(struct device *dev)345{346	struct emc2305_data *data = dev_get_drvdata(dev);347	int i;348 349	/* Unregister cooling device. */350	for (i = 0; i < EMC2305_PWM_MAX; i++)351		if (data->cdev_data[i].cdev)352			thermal_cooling_device_unregister(data->cdev_data[i].cdev);353}354 355static umode_t356emc2305_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel)357{358	int max_channel = emc2305_get_max_channel(data);359 360	/* Don't show channels which are not physically connected. */361	if (channel >= max_channel)362		return 0;363	switch (type) {364	case hwmon_fan:365		switch (attr) {366		case hwmon_fan_input:367			return 0444;368		case hwmon_fan_fault:369			return 0444;370		default:371			break;372		}373		break;374	case hwmon_pwm:375		switch (attr) {376		case hwmon_pwm_input:377			return 0644;378		default:379			break;380		}381		break;382	default:383		break;384	}385 386	return 0;387};388 389static int390emc2305_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long val)391{392	struct emc2305_data *data = dev_get_drvdata(dev);393	int cdev_idx;394 395	switch (type) {396	case hwmon_pwm:397		switch (attr) {398		case hwmon_pwm_input:399			/* If thermal is configured - handle PWM limit setting. */400			if (IS_REACHABLE(CONFIG_THERMAL)) {401				if (data->pwm_separate)402					cdev_idx = channel;403				else404					cdev_idx = 0;405				data->cdev_data[cdev_idx].last_hwmon_state =406					EMC2305_PWM_DUTY2STATE(val, data->max_state,407							       EMC2305_FAN_MAX);408				/*409				 * Update PWM only in case requested state is not less than the410				 * last thermal state.411				 */412				if (data->cdev_data[cdev_idx].last_hwmon_state >=413				    data->cdev_data[cdev_idx].last_thermal_state)414					return __emc2305_set_cur_state(data, cdev_idx,415							data->cdev_data[cdev_idx].last_hwmon_state);416				return 0;417			}418			return emc2305_set_pwm(dev, val, channel);419		default:420			break;421		}422		break;423	default:424		break;425	}426 427	return -EOPNOTSUPP;428};429 430static int431emc2305_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val)432{433	int ret;434 435	switch (type) {436	case hwmon_fan:437		switch (attr) {438		case hwmon_fan_input:439			ret = emc2305_show_fan(dev, channel);440			if (ret < 0)441				return ret;442			*val = ret;443			return 0;444		case hwmon_fan_fault:445			ret = emc2305_show_fault(dev, channel);446			if (ret < 0)447				return ret;448			*val = ret;449			return 0;450		default:451			break;452		}453		break;454	case hwmon_pwm:455		switch (attr) {456		case hwmon_pwm_input:457			ret = emc2305_show_pwm(dev, channel);458			if (ret < 0)459				return ret;460			*val = ret;461			return 0;462		default:463			break;464		}465		break;466	default:467		break;468	}469 470	return -EOPNOTSUPP;471};472 473static const struct hwmon_ops emc2305_ops = {474	.is_visible = emc2305_is_visible,475	.read = emc2305_read,476	.write = emc2305_write,477};478 479static const struct hwmon_channel_info * const emc2305_info[] = {480	HWMON_CHANNEL_INFO(fan,481			   HWMON_F_INPUT | HWMON_F_FAULT,482			   HWMON_F_INPUT | HWMON_F_FAULT,483			   HWMON_F_INPUT | HWMON_F_FAULT,484			   HWMON_F_INPUT | HWMON_F_FAULT,485			   HWMON_F_INPUT | HWMON_F_FAULT),486	HWMON_CHANNEL_INFO(pwm,487			   HWMON_PWM_INPUT,488			   HWMON_PWM_INPUT,489			   HWMON_PWM_INPUT,490			   HWMON_PWM_INPUT,491			   HWMON_PWM_INPUT),492	NULL493};494 495static const struct hwmon_chip_info emc2305_chip_info = {496	.ops = &emc2305_ops,497	.info = emc2305_info,498};499 500static int emc2305_identify(struct device *dev)501{502	struct i2c_client *client = to_i2c_client(dev);503	struct emc2305_data *data = i2c_get_clientdata(client);504	int ret;505 506	ret = i2c_smbus_read_byte_data(client, EMC2305_REG_PRODUCT_ID);507	if (ret < 0)508		return ret;509 510	switch (ret) {511	case EMC2305:512		data->pwm_num = 5;513		break;514	case EMC2303:515		data->pwm_num = 3;516		break;517	case EMC2302:518		data->pwm_num = 2;519		break;520	case EMC2301:521		data->pwm_num = 1;522		break;523	default:524		return -ENODEV;525	}526 527	return 0;528}529 530static int emc2305_probe(struct i2c_client *client)531{532	struct i2c_adapter *adapter = client->adapter;533	struct device *dev = &client->dev;534	struct emc2305_data *data;535	struct emc2305_platform_data *pdata;536	int vendor;537	int ret;538	int i;539 540	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))541		return -ENODEV;542 543	vendor = i2c_smbus_read_byte_data(client, EMC2305_REG_VENDOR);544	if (vendor != EMC2305_VENDOR)545		return -ENODEV;546 547	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);548	if (!data)549		return -ENOMEM;550 551	i2c_set_clientdata(client, data);552	data->client = client;553 554	ret = emc2305_identify(dev);555	if (ret)556		return ret;557 558	pdata = dev_get_platdata(&client->dev);559	if (pdata) {560		if (!pdata->max_state || pdata->max_state > EMC2305_FAN_MAX_STATE)561			return -EINVAL;562		data->max_state = pdata->max_state;563		/*564		 * Validate a number of active PWM channels. Note that565		 * configured number can be less than the actual maximum566		 * supported by the device.567		 */568		if (!pdata->pwm_num || pdata->pwm_num > EMC2305_PWM_MAX)569			return -EINVAL;570		data->pwm_num = pdata->pwm_num;571		data->pwm_separate = pdata->pwm_separate;572		for (i = 0; i < EMC2305_PWM_MAX; i++)573			data->pwm_min[i] = pdata->pwm_min[i];574	} else {575		data->max_state = EMC2305_FAN_MAX_STATE;576		data->pwm_separate = false;577		for (i = 0; i < EMC2305_PWM_MAX; i++)578			data->pwm_min[i] = EMC2305_FAN_MIN;579	}580 581	data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "emc2305", data,582							       &emc2305_chip_info, NULL);583	if (IS_ERR(data->hwmon_dev))584		return PTR_ERR(data->hwmon_dev);585 586	if (IS_REACHABLE(CONFIG_THERMAL)) {587		ret = emc2305_set_tz(dev);588		if (ret != 0)589			return ret;590	}591 592	for (i = 0; i < data->pwm_num; i++) {593		ret = i2c_smbus_write_byte_data(client, EMC2305_REG_FAN_MIN_DRIVE(i),594						data->pwm_min[i]);595		if (ret < 0)596			return ret;597	}598 599	return 0;600}601 602static void emc2305_remove(struct i2c_client *client)603{604	struct device *dev = &client->dev;605 606	if (IS_REACHABLE(CONFIG_THERMAL))607		emc2305_unset_tz(dev);608}609 610static struct i2c_driver emc2305_driver = {611	.driver = {612		.name = "emc2305",613	},614	.probe = emc2305_probe,615	.remove	  = emc2305_remove,616	.id_table = emc2305_ids,617};618 619module_i2c_driver(emc2305_driver);620 621MODULE_AUTHOR("Nvidia");622MODULE_DESCRIPTION("Microchip EMC2305 fan controller driver");623MODULE_LICENSE("GPL");624