brintos

brintos / linux-shallow public Read only

0
0
Text · 15.9 KiB · 33e997b Raw
663 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/***************************************************************************3 *   Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com>           *4 *                                                                         *5 ***************************************************************************/6 7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt8 9#include <linux/bits.h>10#include <linux/minmax.h>11#include <linux/module.h>12#include <linux/mod_devicetable.h>13#include <linux/pm.h>14#include <linux/init.h>15#include <linux/regmap.h>16#include <linux/slab.h>17#include <linux/jiffies.h>18#include <linux/platform_device.h>19#include <linux/hwmon.h>20#include <linux/err.h>21#include <linux/mutex.h>22#include "sch56xx-common.h"23 24#define DRVNAME "sch5627"25#define DEVNAME DRVNAME /* We only support one model */26 27#define SCH5627_HWMON_ID		0xa528#define SCH5627_COMPANY_ID		0x5c29#define SCH5627_PRIMARY_ID		0xa030 31#define SCH5627_REG_BUILD_CODE		0x3932#define SCH5627_REG_BUILD_ID		0x3a33#define SCH5627_REG_HWMON_ID		0x3c34#define SCH5627_REG_HWMON_REV		0x3d35#define SCH5627_REG_COMPANY_ID		0x3e36#define SCH5627_REG_PRIMARY_ID		0x3f37#define SCH5627_REG_CTRL		0x4038 39#define SCH5627_CTRL_START		BIT(0)40#define SCH5627_CTRL_LOCK		BIT(1)41#define SCH5627_CTRL_VBAT		BIT(4)42 43#define SCH5627_NO_TEMPS		844#define SCH5627_NO_FANS			445#define SCH5627_NO_IN			546 47static const u16 SCH5627_REG_TEMP_MSB[SCH5627_NO_TEMPS] = {48	0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x180, 0x181 };49static const u16 SCH5627_REG_TEMP_LSN[SCH5627_NO_TEMPS] = {50	0xE2, 0xE1, 0xE1, 0xE5, 0xE5, 0xE6, 0x182, 0x182 };51static const u16 SCH5627_REG_TEMP_HIGH_NIBBLE[SCH5627_NO_TEMPS] = {52	0, 0, 1, 1, 0, 0, 0, 1 };53static const u16 SCH5627_REG_TEMP_HIGH[SCH5627_NO_TEMPS] = {54	0x61, 0x57, 0x59, 0x5B, 0x5D, 0x5F, 0x184, 0x186 };55static const u16 SCH5627_REG_TEMP_ABS[SCH5627_NO_TEMPS] = {56	0x9B, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x1A8, 0x1A9 };57 58static const u16 SCH5627_REG_FAN[SCH5627_NO_FANS] = {59	0x2C, 0x2E, 0x30, 0x32 };60static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = {61	0x62, 0x64, 0x66, 0x68 };62 63static const u16 SCH5627_REG_PWM_MAP[SCH5627_NO_FANS] = {64	0xA0, 0xA1, 0xA2, 0xA3 };65 66static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = {67	0x22, 0x23, 0x24, 0x25, 0x189 };68static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = {69	0xE4, 0xE4, 0xE3, 0xE3, 0x18A };70static const u16 SCH5627_REG_IN_HIGH_NIBBLE[SCH5627_NO_IN] = {71	1, 0, 1, 0, 1 };72static const u16 SCH5627_REG_IN_FACTOR[SCH5627_NO_IN] = {73	10745, 3660, 9765, 10745, 3660 };74static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {75	"VCC", "VTT", "VBAT", "VTR", "V_IN" };76 77struct sch5627_data {78	struct regmap *regmap;79	unsigned short addr;80	u8 control;81 82	struct mutex update_lock;83	unsigned long last_battery;	/* In jiffies */84	char temp_valid;		/* !=0 if following fields are valid */85	char fan_valid;86	char in_valid;87	unsigned long temp_last_updated;	/* In jiffies */88	unsigned long fan_last_updated;89	unsigned long in_last_updated;90	u16 temp[SCH5627_NO_TEMPS];91	u16 fan[SCH5627_NO_FANS];92	u16 in[SCH5627_NO_IN];93};94 95static const struct regmap_range sch5627_tunables_ranges[] = {96	regmap_reg_range(0x57, 0x57),97	regmap_reg_range(0x59, 0x59),98	regmap_reg_range(0x5B, 0x5B),99	regmap_reg_range(0x5D, 0x5D),100	regmap_reg_range(0x5F, 0x5F),101	regmap_reg_range(0x61, 0x69),102	regmap_reg_range(0x96, 0x9B),103	regmap_reg_range(0xA0, 0xA3),104	regmap_reg_range(0x184, 0x184),105	regmap_reg_range(0x186, 0x186),106	regmap_reg_range(0x1A8, 0x1A9),107};108 109static const struct regmap_access_table sch5627_tunables_table = {110	.yes_ranges = sch5627_tunables_ranges,111	.n_yes_ranges = ARRAY_SIZE(sch5627_tunables_ranges),112};113 114static const struct regmap_config sch5627_regmap_config = {115	.reg_bits = 16,116	.val_bits = 8,117	.wr_table = &sch5627_tunables_table,118	.rd_table = &sch5627_tunables_table,119	.cache_type = REGCACHE_MAPLE,120	.use_single_read = true,121	.use_single_write = true,122	.can_sleep = true,123};124 125static int sch5627_update_temp(struct sch5627_data *data)126{127	int ret = 0;128	int i, val;129 130	mutex_lock(&data->update_lock);131 132	/* Cache the values for 1 second */133	if (time_after(jiffies, data->temp_last_updated + HZ) || !data->temp_valid) {134		for (i = 0; i < SCH5627_NO_TEMPS; i++) {135			val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_TEMP_MSB[i],136							 SCH5627_REG_TEMP_LSN[i],137							 SCH5627_REG_TEMP_HIGH_NIBBLE[i]);138			if (unlikely(val < 0)) {139				ret = val;140				goto abort;141			}142			data->temp[i] = val;143		}144		data->temp_last_updated = jiffies;145		data->temp_valid = 1;146	}147abort:148	mutex_unlock(&data->update_lock);149	return ret;150}151 152static int sch5627_update_fan(struct sch5627_data *data)153{154	int ret = 0;155	int i, val;156 157	mutex_lock(&data->update_lock);158 159	/* Cache the values for 1 second */160	if (time_after(jiffies, data->fan_last_updated + HZ) || !data->fan_valid) {161		for (i = 0; i < SCH5627_NO_FANS; i++) {162			val = sch56xx_read_virtual_reg16(data->addr, SCH5627_REG_FAN[i]);163			if (unlikely(val < 0)) {164				ret = val;165				goto abort;166			}167			data->fan[i] = val;168		}169		data->fan_last_updated = jiffies;170		data->fan_valid = 1;171	}172abort:173	mutex_unlock(&data->update_lock);174	return ret;175}176 177static int sch5627_update_in(struct sch5627_data *data)178{179	int ret = 0;180	int i, val;181 182	mutex_lock(&data->update_lock);183 184	/* Trigger a Vbat voltage measurement every 5 minutes */185	if (time_after(jiffies, data->last_battery + 300 * HZ)) {186		sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL,187					  data->control | SCH5627_CTRL_VBAT);188		data->last_battery = jiffies;189	}190 191	/* Cache the values for 1 second */192	if (time_after(jiffies, data->in_last_updated + HZ) || !data->in_valid) {193		for (i = 0; i < SCH5627_NO_IN; i++) {194			val = sch56xx_read_virtual_reg12(data->addr, SCH5627_REG_IN_MSB[i],195							 SCH5627_REG_IN_LSN[i],196							 SCH5627_REG_IN_HIGH_NIBBLE[i]);197			if (unlikely(val < 0)) {198				ret = val;199				goto abort;200			}201			data->in[i] = val;202		}203		data->in_last_updated = jiffies;204		data->in_valid = 1;205	}206abort:207	mutex_unlock(&data->update_lock);208	return ret;209}210 211static int reg_to_temp(u16 reg)212{213	return (reg * 625) / 10 - 64000;214}215 216static int reg_to_temp_limit(u8 reg)217{218	return (reg - 64) * 1000;219}220 221static int reg_to_rpm(u16 reg)222{223	if (reg == 0)224		return -EIO;225	if (reg == 0xffff)226		return 0;227 228	return 5400540 / reg;229}230 231static u8 sch5627_temp_limit_to_reg(long value)232{233	long limit = (value / 1000) + 64;234 235	return clamp_val(limit, 0, U8_MAX);236}237 238static u16 sch5627_rpm_to_reg(long value)239{240	long pulses;241 242	if (value <= 0)243		return U16_MAX - 1;244 245	pulses = 5400540 / value;246 247	return clamp_val(pulses, 1, U16_MAX - 1);248}249 250static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,251				  int channel)252{253	const struct sch5627_data *data = drvdata;254 255	/* Once the lock bit is set, the virtual registers become read-only256	 * until the next power cycle.257	 */258	if (data->control & SCH5627_CTRL_LOCK)259		return 0444;260 261	switch (type) {262	case hwmon_temp:263		switch (attr) {264		case hwmon_temp_max:265		case hwmon_temp_crit:266			return 0644;267		default:268			break;269		}270		break;271	case hwmon_fan:272		switch (attr) {273		case hwmon_fan_min:274			return 0644;275		default:276			break;277		}278		break;279	case hwmon_pwm:280		switch (attr) {281		case hwmon_pwm_auto_channels_temp:282			return 0644;283		default:284			break;285		}286		break;287	default:288		break;289	}290 291	return 0444;292}293 294static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,295			long *val)296{297	struct sch5627_data *data = dev_get_drvdata(dev);298	int ret, value;299 300	switch (type) {301	case hwmon_temp:302		switch (attr) {303		case hwmon_temp_input:304			ret = sch5627_update_temp(data);305			if (ret < 0)306				return ret;307 308			*val = reg_to_temp(data->temp[channel]);309			return 0;310		case hwmon_temp_max:311			ret = regmap_read(data->regmap, SCH5627_REG_TEMP_ABS[channel], &value);312			if (ret < 0)313				return ret;314 315			*val = reg_to_temp_limit((u8)value);316			return 0;317		case hwmon_temp_crit:318			ret = regmap_read(data->regmap, SCH5627_REG_TEMP_HIGH[channel], &value);319			if (ret < 0)320				return ret;321 322			*val = reg_to_temp_limit((u8)value);323			return 0;324		case hwmon_temp_fault:325			ret = sch5627_update_temp(data);326			if (ret < 0)327				return ret;328 329			*val = (data->temp[channel] == 0);330			return 0;331		default:332			break;333		}334		break;335	case hwmon_fan:336		switch (attr) {337		case hwmon_fan_input:338			ret = sch5627_update_fan(data);339			if (ret < 0)340				return ret;341 342			ret = reg_to_rpm(data->fan[channel]);343			if (ret < 0)344				return ret;345 346			*val = ret;347			return 0;348		case hwmon_fan_min:349			ret = sch56xx_regmap_read16(data->regmap, SCH5627_REG_FAN_MIN[channel],350						    &value);351			if (ret < 0)352				return ret;353 354			ret = reg_to_rpm((u16)value);355			if (ret < 0)356				return ret;357 358			*val = ret;359			return 0;360		case hwmon_fan_fault:361			ret = sch5627_update_fan(data);362			if (ret < 0)363				return ret;364 365			*val = (data->fan[channel] == 0xffff);366			return 0;367		default:368			break;369		}370		break;371	case hwmon_pwm:372		switch (attr) {373		case hwmon_pwm_auto_channels_temp:374			ret = regmap_read(data->regmap, SCH5627_REG_PWM_MAP[channel], &value);375			if (ret < 0)376				return ret;377 378			*val = value;379			return 0;380		default:381			break;382		}383		break;384	case hwmon_in:385		ret = sch5627_update_in(data);386		if (ret < 0)387			return ret;388		switch (attr) {389		case hwmon_in_input:390			*val = DIV_ROUND_CLOSEST(data->in[channel] * SCH5627_REG_IN_FACTOR[channel],391						 10000);392			return 0;393		default:394			break;395		}396		break;397	default:398		break;399	}400 401	return -EOPNOTSUPP;402}403 404static int sch5627_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,405			       int channel, const char **str)406{407	switch (type) {408	case hwmon_in:409		switch (attr) {410		case hwmon_in_label:411			*str = SCH5627_IN_LABELS[channel];412			return 0;413		default:414			break;415		}416		break;417	default:418		break;419	}420 421	return -EOPNOTSUPP;422}423 424static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,425			 long val)426{427	struct sch5627_data *data = dev_get_drvdata(dev);428	u16 fan;429	u8 temp;430 431	switch (type) {432	case hwmon_temp:433		temp = sch5627_temp_limit_to_reg(val);434 435		switch (attr) {436		case hwmon_temp_max:437			return regmap_write(data->regmap, SCH5627_REG_TEMP_ABS[channel], temp);438		case hwmon_temp_crit:439			return regmap_write(data->regmap, SCH5627_REG_TEMP_HIGH[channel], temp);440		default:441			break;442		}443		break;444	case hwmon_fan:445		switch (attr) {446		case hwmon_fan_min:447			fan = sch5627_rpm_to_reg(val);448 449			return sch56xx_regmap_write16(data->regmap, SCH5627_REG_FAN_MIN[channel],450						      fan);451		default:452			break;453		}454		break;455	case hwmon_pwm:456		switch (attr) {457		case hwmon_pwm_auto_channels_temp:458			/* registers are 8 bit wide */459			if (val > U8_MAX || val < 0)460				return -EINVAL;461 462			return regmap_write(data->regmap, SCH5627_REG_PWM_MAP[channel], val);463		default:464			break;465		}466		break;467	default:468		break;469	}470 471	return -EOPNOTSUPP;472}473 474static const struct hwmon_ops sch5627_ops = {475	.is_visible = sch5627_is_visible,476	.read = sch5627_read,477	.read_string = sch5627_read_string,478	.write = sch5627_write,479};480 481static const struct hwmon_channel_info * const sch5627_info[] = {482	HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),483	HWMON_CHANNEL_INFO(temp,484			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,485			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,486			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,487			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,488			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,489			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,490			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT,491			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | HWMON_T_FAULT492			   ),493	HWMON_CHANNEL_INFO(fan,494			   HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,495			   HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,496			   HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,497			   HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT498			   ),499	HWMON_CHANNEL_INFO(pwm,500			   HWMON_PWM_AUTO_CHANNELS_TEMP,501			   HWMON_PWM_AUTO_CHANNELS_TEMP,502			   HWMON_PWM_AUTO_CHANNELS_TEMP,503			   HWMON_PWM_AUTO_CHANNELS_TEMP504			   ),505	HWMON_CHANNEL_INFO(in,506			   HWMON_I_INPUT | HWMON_I_LABEL,507			   HWMON_I_INPUT | HWMON_I_LABEL,508			   HWMON_I_INPUT | HWMON_I_LABEL,509			   HWMON_I_INPUT | HWMON_I_LABEL,510			   HWMON_I_INPUT511			   ),512	NULL513};514 515static const struct hwmon_chip_info sch5627_chip_info = {516	.ops = &sch5627_ops,517	.info = sch5627_info,518};519 520static int sch5627_probe(struct platform_device *pdev)521{522	struct sch5627_data *data;523	struct device *hwmon_dev;524	int build_code, build_id, hwmon_rev, val;525 526	data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),527			    GFP_KERNEL);528	if (!data)529		return -ENOMEM;530 531	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;532	mutex_init(&data->update_lock);533	platform_set_drvdata(pdev, data);534 535	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_HWMON_ID);536	if (val < 0)537		return val;538 539	if (val != SCH5627_HWMON_ID) {540		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon",541		       val, SCH5627_HWMON_ID);542		return -ENODEV;543	}544 545	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_COMPANY_ID);546	if (val < 0)547		return val;548 549	if (val != SCH5627_COMPANY_ID) {550		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company",551		       val, SCH5627_COMPANY_ID);552		return -ENODEV;553	}554 555	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PRIMARY_ID);556	if (val < 0)557		return val;558 559	if (val != SCH5627_PRIMARY_ID) {560		pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary",561		       val, SCH5627_PRIMARY_ID);562		return -ENODEV;563	}564 565	build_code = sch56xx_read_virtual_reg(data->addr,566					      SCH5627_REG_BUILD_CODE);567	if (build_code < 0)568		return build_code;569 570	build_id = sch56xx_read_virtual_reg16(data->addr,571					      SCH5627_REG_BUILD_ID);572	if (build_id < 0)573		return build_id;574 575	hwmon_rev = sch56xx_read_virtual_reg(data->addr,576					     SCH5627_REG_HWMON_REV);577	if (hwmon_rev < 0)578		return hwmon_rev;579 580	val = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_CTRL);581	if (val < 0)582		return val;583 584	data->control = val;585	if (!(data->control & SCH5627_CTRL_START)) {586		pr_err("hardware monitoring not enabled\n");587		return -ENODEV;588	}589 590	data->regmap = devm_regmap_init_sch56xx(&pdev->dev, &data->update_lock, data->addr,591						&sch5627_regmap_config);592	if (IS_ERR(data->regmap))593		return PTR_ERR(data->regmap);594 595	/* Trigger a Vbat voltage measurement, so that we get a valid reading596	   the first time we read Vbat */597	sch56xx_write_virtual_reg(data->addr, SCH5627_REG_CTRL, data->control | SCH5627_CTRL_VBAT);598	data->last_battery = jiffies;599 600	pr_info("found %s chip at %#hx\n", DEVNAME, data->addr);601	pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n",602		build_code, build_id, hwmon_rev);603 604	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, DEVNAME, data,605							 &sch5627_chip_info, NULL);606	if (IS_ERR(hwmon_dev))607		return PTR_ERR(hwmon_dev);608 609	/* Note failing to register the watchdog is not a fatal error */610	sch56xx_watchdog_register(&pdev->dev, data->addr,611				  (build_code << 24) | (build_id << 8) | hwmon_rev,612				  &data->update_lock, 1);613 614	return 0;615}616 617static int sch5627_suspend(struct device *dev)618{619	struct sch5627_data *data = dev_get_drvdata(dev);620 621	regcache_cache_only(data->regmap, true);622	regcache_mark_dirty(data->regmap);623 624	return 0;625}626 627static int sch5627_resume(struct device *dev)628{629	struct sch5627_data *data = dev_get_drvdata(dev);630 631	regcache_cache_only(data->regmap, false);632	/* We must not access the virtual registers when the lock bit is set */633	if (data->control & SCH5627_CTRL_LOCK)634		return regcache_drop_region(data->regmap, 0, U16_MAX);635 636	return regcache_sync(data->regmap);637}638 639static DEFINE_SIMPLE_DEV_PM_OPS(sch5627_dev_pm_ops, sch5627_suspend, sch5627_resume);640 641static const struct platform_device_id sch5627_device_id[] = {642	{643		.name = "sch5627",644	},645	{ }646};647MODULE_DEVICE_TABLE(platform, sch5627_device_id);648 649static struct platform_driver sch5627_driver = {650	.driver = {651		.name	= DRVNAME,652		.pm	= pm_sleep_ptr(&sch5627_dev_pm_ops),653	},654	.probe		= sch5627_probe,655	.id_table	= sch5627_device_id,656};657 658module_platform_driver(sch5627_driver);659 660MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver");661MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");662MODULE_LICENSE("GPL");663