diff options
Diffstat (limited to 'drivers/hwmon/pmbus/ibm-cffps.c')
| -rw-r--r-- | drivers/hwmon/pmbus/ibm-cffps.c | 272 | 
1 files changed, 118 insertions, 154 deletions
diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c index e3294a1a54bb..76e72e9acda7 100644 --- a/drivers/hwmon/pmbus/ibm-cffps.c +++ b/drivers/hwmon/pmbus/ibm-cffps.c @@ -18,12 +18,6 @@  #include "pmbus.h" -#define CFFPS_MFG_ID_CMD                        0x99 -#define CFFPS_FRU_CMD				0x9A -#define CFFPS_PN_CMD				0x9B -#define CFFPS_HEADER_CMD			0x9C -#define CFFPS_SN_CMD				0x9E -#define CFFPS_MAX_POWER_OUT_CMD			0xA7  #define CFFPS_CCIN_CMD				0xBD  #define CFFPS_FW_CMD				0xFA  #define CFFPS1_FW_NUM_BYTES			4 @@ -32,7 +26,7 @@  #define CFFPS_12VCS_VOUT_CMD			0xDE  #define CFFPS_INPUT_HISTORY_CMD			0xD6 -#define CFFPS_INPUT_HISTORY_SIZE		100 +#define CFFPS_INPUT_HISTORY_SIZE		101  #define CFFPS_CCIN_REVISION			GENMASK(7, 0)  #define CFFPS_CCIN_REVISION_LEGACY		 0xde @@ -57,13 +51,7 @@  #define CFFPS_BLINK_RATE_MS			250  enum { -	CFFPS_DEBUGFS_INPUT_HISTORY = 0, -	CFFPS_DEBUGFS_MFG_ID, -	CFFPS_DEBUGFS_FRU, -	CFFPS_DEBUGFS_PN, -	CFFPS_DEBUGFS_HEADER, -	CFFPS_DEBUGFS_SN, -	CFFPS_DEBUGFS_MAX_POWER_OUT, +	CFFPS_DEBUGFS_MAX_POWER_OUT = 0,  	CFFPS_DEBUGFS_CCIN,  	CFFPS_DEBUGFS_FW,  	CFFPS_DEBUGFS_ON_OFF_CONFIG, @@ -72,19 +60,11 @@ enum {  enum versions { cffps1, cffps2, cffps_unknown }; -struct ibm_cffps_input_history { -	struct mutex update_lock; -	unsigned long last_update; - -	u8 byte_count; -	u8 data[CFFPS_INPUT_HISTORY_SIZE]; -}; -  struct ibm_cffps {  	enum versions version;  	struct i2c_client *client; -	struct ibm_cffps_input_history input_history; +	u8 input_history[CFFPS_INPUT_HISTORY_SIZE];  	int debugfs_entries[CFFPS_DEBUGFS_NUM_ENTRIES]; @@ -93,118 +73,98 @@ struct ibm_cffps {  	struct led_classdev led;  }; -static const struct i2c_device_id ibm_cffps_id[]; -  #define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)]) -static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu, -					    char __user *buf, size_t count, -					    loff_t *ppos) +static ssize_t ibm_cffps_debugfs_read_input_history(struct file *file, char __user *buf, +						    size_t count, loff_t *ppos)  {  	int rc; -	u8 msgbuf0[1] = { CFFPS_INPUT_HISTORY_CMD }; -	u8 msgbuf1[CFFPS_INPUT_HISTORY_SIZE + 1] = { 0 }; +	u8 cmd = CFFPS_INPUT_HISTORY_CMD; +	struct ibm_cffps *psu = file->private_data;  	struct i2c_msg msg[2] = {  		{  			.addr = psu->client->addr,  			.flags = psu->client->flags,  			.len = 1, -			.buf = msgbuf0, +			.buf = &cmd,  		}, {  			.addr = psu->client->addr,  			.flags = psu->client->flags | I2C_M_RD, -			.len = CFFPS_INPUT_HISTORY_SIZE + 1, -			.buf = msgbuf1, +			.len = CFFPS_INPUT_HISTORY_SIZE, +			.buf = psu->input_history,  		},  	};  	if (!*ppos) { -		mutex_lock(&psu->input_history.update_lock); -		if (time_after(jiffies, psu->input_history.last_update + HZ)) { -			/* -			 * Use a raw i2c transfer, since we need more bytes -			 * than Linux I2C supports through smbus xfr (only 32). -			 */ -			rc = i2c_transfer(psu->client->adapter, msg, 2); -			if (rc < 0) { -				mutex_unlock(&psu->input_history.update_lock); -				return rc; -			} +		rc = pmbus_lock_interruptible(psu->client); +		if (rc) +			return rc; -			psu->input_history.byte_count = msgbuf1[0]; -			memcpy(psu->input_history.data, &msgbuf1[1], -			       CFFPS_INPUT_HISTORY_SIZE); -			psu->input_history.last_update = jiffies; +		rc = pmbus_set_page(psu->client, 0, 0xff); +		if (rc) { +			pmbus_unlock(psu->client); +			return rc;  		} -		mutex_unlock(&psu->input_history.update_lock); +		/* +		 * Use a raw i2c transfer, since we need more bytes +		 * than Linux I2C supports through smbus xfr (only 32). +		 */ +		rc = i2c_transfer(psu->client->adapter, msg, 2); +		pmbus_unlock(psu->client); +		if (rc < 0) +			return rc;  	}  	return simple_read_from_buffer(buf, count, ppos, -				       psu->input_history.data, -				       psu->input_history.byte_count); +				       psu->input_history + 1, +				       psu->input_history[0]);  } +static const struct file_operations ibm_cffps_input_history_fops = { +	.llseek = noop_llseek, +	.read = ibm_cffps_debugfs_read_input_history, +	.open = simple_open, +}; +  static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,  				      size_t count, loff_t *ppos)  { -	u8 cmd;  	int i, rc;  	int *idxp = file->private_data;  	int idx = *idxp;  	struct ibm_cffps *psu = to_psu(idxp, idx);  	char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 }; -	pmbus_set_page(psu->client, 0, 0xff); +	rc = pmbus_lock_interruptible(psu->client); +	if (rc) +		return rc; + +	rc = pmbus_set_page(psu->client, 0, 0xff); +	if (rc) +		goto unlock;  	switch (idx) { -	case CFFPS_DEBUGFS_INPUT_HISTORY: -		return ibm_cffps_read_input_history(psu, buf, count, ppos); -	case CFFPS_DEBUGFS_MFG_ID: -		cmd = CFFPS_MFG_ID_CMD; -		break; -	case CFFPS_DEBUGFS_FRU: -		cmd = CFFPS_FRU_CMD; -		break; -	case CFFPS_DEBUGFS_PN: -		cmd = CFFPS_PN_CMD; -		break; -	case CFFPS_DEBUGFS_HEADER: -		cmd = CFFPS_HEADER_CMD; -		break; -	case CFFPS_DEBUGFS_SN: -		cmd = CFFPS_SN_CMD; -		break;  	case CFFPS_DEBUGFS_MAX_POWER_OUT: -		if (psu->version == cffps1) { -			rc = i2c_smbus_read_word_swapped(psu->client, -					CFFPS_MAX_POWER_OUT_CMD); -		} else { -			rc = i2c_smbus_read_word_data(psu->client, -					CFFPS_MAX_POWER_OUT_CMD); -		} - -		if (rc < 0) -			return rc; - -		rc = snprintf(data, I2C_SMBUS_BLOCK_MAX, "%d", rc); -		goto done; +		if (psu->version == cffps1) +			rc = i2c_smbus_read_word_swapped(psu->client, PMBUS_MFR_POUT_MAX); +		else +			rc = i2c_smbus_read_word_data(psu->client, PMBUS_MFR_POUT_MAX); +		if (rc >= 0) +			rc = snprintf(data, I2C_SMBUS_BLOCK_MAX, "%d", rc); +		break;  	case CFFPS_DEBUGFS_CCIN:  		rc = i2c_smbus_read_word_swapped(psu->client, CFFPS_CCIN_CMD); -		if (rc < 0) -			return rc; - -		rc = snprintf(data, 5, "%04X", rc); -		goto done; +		if (rc >= 0) +			rc = snprintf(data, 5, "%04X", rc); +		break;  	case CFFPS_DEBUGFS_FW:  		switch (psu->version) {  		case cffps1:  			for (i = 0; i < CFFPS1_FW_NUM_BYTES; ++i) { -				rc = i2c_smbus_read_byte_data(psu->client, -							      CFFPS_FW_CMD + -								i); +				rc = i2c_smbus_read_byte_data(psu->client, CFFPS_FW_CMD + i);  				if (rc < 0) -					return rc; +					goto unlock;  				snprintf(&data[i * 2], 3, "%02X", rc);  			} @@ -213,11 +173,9 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,  			break;  		case cffps2:  			for (i = 0; i < CFFPS2_FW_NUM_WORDS; ++i) { -				rc = i2c_smbus_read_word_data(psu->client, -							      CFFPS_FW_CMD + -								i); +				rc = i2c_smbus_read_word_data(psu->client, CFFPS_FW_CMD + i);  				if (rc < 0) -					return rc; +					goto unlock;  				snprintf(&data[i * 4], 5, "%04X", rc);  			} @@ -225,26 +183,25 @@ static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,  			rc = i * 4;  			break;  		default: -			return -EOPNOTSUPP; +			rc = -EOPNOTSUPP; +			break;  		} -		goto done; +		break;  	case CFFPS_DEBUGFS_ON_OFF_CONFIG: -		rc = i2c_smbus_read_byte_data(psu->client, -					      PMBUS_ON_OFF_CONFIG); -		if (rc < 0) -			return rc; - -		rc = snprintf(data, 3, "%02x", rc); -		goto done; +		rc = i2c_smbus_read_byte_data(psu->client, PMBUS_ON_OFF_CONFIG); +		if (rc >= 0) +			rc = snprintf(data, 3, "%02x", rc); +		break;  	default: -		return -EINVAL; +		rc = -EINVAL; +		break;  	} -	rc = i2c_smbus_read_block_data(psu->client, cmd, data); +unlock: +	pmbus_unlock(psu->client);  	if (rc < 0)  		return rc; -done:  	data[rc] = '\n';  	rc += 2; @@ -263,14 +220,22 @@ static ssize_t ibm_cffps_debugfs_write(struct file *file,  	switch (idx) {  	case CFFPS_DEBUGFS_ON_OFF_CONFIG: -		pmbus_set_page(psu->client, 0, 0xff); -  		rc = simple_write_to_buffer(&data, 1, ppos, buf, count);  		if (rc <= 0)  			return rc; -		rc = i2c_smbus_write_byte_data(psu->client, -					       PMBUS_ON_OFF_CONFIG, data); +		rc = pmbus_lock_interruptible(psu->client); +		if (rc) +			return rc; + +		rc = pmbus_set_page(psu->client, 0, 0xff); +		if (rc) { +			pmbus_unlock(psu->client); +			return rc; +		} + +		rc = i2c_smbus_write_byte_data(psu->client, PMBUS_ON_OFF_CONFIG, data); +		pmbus_unlock(psu->client);  		if (rc)  			return rc; @@ -396,10 +361,19 @@ static int ibm_cffps_led_brightness_set(struct led_classdev *led_cdev,  	dev_dbg(&psu->client->dev, "LED brightness set: %d. Command: %d.\n",  		brightness, next_led_state); -	pmbus_set_page(psu->client, 0, 0xff); +	rc = pmbus_lock_interruptible(psu->client); +	if (rc) +		return rc; + +	rc = pmbus_set_page(psu->client, 0, 0xff); +	if (rc) { +		pmbus_unlock(psu->client); +		return rc; +	}  	rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,  				       next_led_state); +	pmbus_unlock(psu->client);  	if (rc < 0)  		return rc; @@ -418,10 +392,19 @@ static int ibm_cffps_led_blink_set(struct led_classdev *led_cdev,  	dev_dbg(&psu->client->dev, "LED blink set.\n"); -	pmbus_set_page(psu->client, 0, 0xff); +	rc = pmbus_lock_interruptible(psu->client); +	if (rc) +		return rc; + +	rc = pmbus_set_page(psu->client, 0, 0xff); +	if (rc) { +		pmbus_unlock(psu->client); +		return rc; +	}  	rc = i2c_smbus_write_byte_data(psu->client, CFFPS_SYS_CONFIG_CMD,  				       CFFPS_LED_BLINK); +	pmbus_unlock(psu->client);  	if (rc < 0)  		return rc; @@ -474,9 +457,11 @@ static struct pmbus_driver_info ibm_cffps_info[] = {  			PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |  			PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |  			PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_VMON, -		.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | -			PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 | -			PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT, +		.func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | +			PMBUS_HAVE_PIN | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | +			PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_VOUT | +			PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_STATUS_INPUT | +			PMBUS_HAVE_STATUS_TEMP,  		.read_byte_data = ibm_cffps_read_byte_data,  		.read_word_data = ibm_cffps_read_word_data,  	}, @@ -486,12 +471,19 @@ static struct pmbus_platform_data ibm_cffps_pdata = {  	.flags = PMBUS_SKIP_STATUS_CHECK | PMBUS_NO_CAPABILITY,  }; +static const struct i2c_device_id ibm_cffps_id[] = { +	{ "ibm_cffps1", cffps1 }, +	{ "ibm_cffps2", cffps2 }, +	{ "ibm_cffps", cffps_unknown }, +	{} +}; +MODULE_DEVICE_TABLE(i2c, ibm_cffps_id); +  static int ibm_cffps_probe(struct i2c_client *client)  {  	int i, rc;  	enum versions vs = cffps_unknown;  	struct dentry *debugfs; -	struct dentry *ibm_cffps_dir;  	struct ibm_cffps *psu;  	const void *md = of_device_get_match_data(&client->dev);  	const struct i2c_device_id *id; @@ -560,8 +552,6 @@ static int ibm_cffps_probe(struct i2c_client *client)  	psu->version = vs;  	psu->client = client; -	mutex_init(&psu->input_history.update_lock); -	psu->input_history.last_update = jiffies - HZ;  	ibm_cffps_create_led_class(psu); @@ -570,55 +560,29 @@ static int ibm_cffps_probe(struct i2c_client *client)  	if (!debugfs)  		return 0; -	ibm_cffps_dir = debugfs_create_dir(client->name, debugfs); -	if (!ibm_cffps_dir) -		return 0; -  	for (i = 0; i < CFFPS_DEBUGFS_NUM_ENTRIES; ++i)  		psu->debugfs_entries[i] = i; -	debugfs_create_file("input_history", 0444, ibm_cffps_dir, -			    &psu->debugfs_entries[CFFPS_DEBUGFS_INPUT_HISTORY], -			    &ibm_cffps_fops); -	debugfs_create_file("mfg_id", 0444, ibm_cffps_dir, -			    &psu->debugfs_entries[CFFPS_DEBUGFS_MFG_ID], -			    &ibm_cffps_fops); -	debugfs_create_file("fru", 0444, ibm_cffps_dir, -			    &psu->debugfs_entries[CFFPS_DEBUGFS_FRU], -			    &ibm_cffps_fops); -	debugfs_create_file("part_number", 0444, ibm_cffps_dir, -			    &psu->debugfs_entries[CFFPS_DEBUGFS_PN], -			    &ibm_cffps_fops); -	debugfs_create_file("header", 0444, ibm_cffps_dir, -			    &psu->debugfs_entries[CFFPS_DEBUGFS_HEADER], -			    &ibm_cffps_fops); -	debugfs_create_file("serial_number", 0444, ibm_cffps_dir, -			    &psu->debugfs_entries[CFFPS_DEBUGFS_SN], -			    &ibm_cffps_fops); -	debugfs_create_file("max_power_out", 0444, ibm_cffps_dir, +	debugfs_create_file("input_history", 0444, debugfs, psu, &ibm_cffps_input_history_fops); +	debugfs_create_file("max_power_out", 0444, debugfs,  			    &psu->debugfs_entries[CFFPS_DEBUGFS_MAX_POWER_OUT],  			    &ibm_cffps_fops); -	debugfs_create_file("ccin", 0444, ibm_cffps_dir, +	debugfs_create_file("ccin", 0444, debugfs,  			    &psu->debugfs_entries[CFFPS_DEBUGFS_CCIN],  			    &ibm_cffps_fops); -	debugfs_create_file("fw_version", 0444, ibm_cffps_dir, +	debugfs_create_file("fw_version", 0444, debugfs,  			    &psu->debugfs_entries[CFFPS_DEBUGFS_FW],  			    &ibm_cffps_fops); -	debugfs_create_file("on_off_config", 0644, ibm_cffps_dir, +	debugfs_create_file("on_off_config", 0644, debugfs,  			    &psu->debugfs_entries[CFFPS_DEBUGFS_ON_OFF_CONFIG],  			    &ibm_cffps_fops); +	/* For compatibility with users of the old naming scheme. */ +	debugfs_create_symlink(client->name, debugfs, "."); +  	return 0;  } -static const struct i2c_device_id ibm_cffps_id[] = { -	{ "ibm_cffps1", cffps1 }, -	{ "ibm_cffps2", cffps2 }, -	{ "ibm_cffps", cffps_unknown }, -	{} -}; -MODULE_DEVICE_TABLE(i2c, ibm_cffps_id); -  static const struct of_device_id ibm_cffps_of_match[] = {  	{  		.compatible = "ibm,cffps1",  |