Lines Matching +full:32 +full:- +full:rail

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * corsair-psu.c - Linux driver for Corsair power supplies with HID sensors interface
12 #include <linux/hwmon-sysfs.h>
29 * - commands are byte sized opcodes
30 * - length is the sum of all bytes of the commands/params
31 * - the micro-controller of most of these PSUs support concatenation in the request and reply,
33 * - the driver uses raw events to be accessible from userspace (though this is not really
35 * - a reply always start with the length and command in the same order the request used it
36 * - length of the reply data is specific to the command used
37 * - some of the commands work on a rail and can be switched to a specific rail (0 = 12v,
39 * - the format of the init command 0xFE is swapped length/command bytes
40 * - parameter bytes amount and values are specific to the command (rail setting is the only
41 * for now that uses non-zero values)
42 * - there are much more commands, especially for configuring the device, but they are not
43 * supported because a wrong command/length can lockup the micro-controller
44 * - the driver supports debugfs for values not fitting into the hwmon class
45 * - not every device class (HXi, RMi or AXi) supports all commands
46 * - it is a pure sensors reading driver (will not support configuring)
49 #define DRIVER_NAME "corsair-psu"
145 return (exp >= 0) ? (result << exp) : (result >> -exp); in corsairpsu_linear11_to_int()
153 memset(priv->cmd_buffer, 0, CMD_BUFFER_SIZE); in corsairpsu_usb_cmd()
154 priv->cmd_buffer[0] = p0; in corsairpsu_usb_cmd()
155 priv->cmd_buffer[1] = p1; in corsairpsu_usb_cmd()
156 priv->cmd_buffer[2] = p2; in corsairpsu_usb_cmd()
158 reinit_completion(&priv->wait_completion); in corsairpsu_usb_cmd()
160 ret = hid_hw_output_report(priv->hdev, priv->cmd_buffer, CMD_BUFFER_SIZE); in corsairpsu_usb_cmd()
164 time = wait_for_completion_timeout(&priv->wait_completion, in corsairpsu_usb_cmd()
167 return -ETIMEDOUT; in corsairpsu_usb_cmd()
174 if (p0 != priv->cmd_buffer[0] || p1 != priv->cmd_buffer[1]) in corsairpsu_usb_cmd()
175 return -EOPNOTSUPP; in corsairpsu_usb_cmd()
178 memcpy(data, priv->cmd_buffer + 2, REPLY_SIZE); in corsairpsu_usb_cmd()
196 ret = corsairpsu_usb_cmd(priv, 3, PSU_CMD_VEND_STR, 0, priv->vendor); in corsairpsu_fwinfo()
200 ret = corsairpsu_usb_cmd(priv, 3, PSU_CMD_PROD_STR, 0, priv->product); in corsairpsu_fwinfo()
207 static int corsairpsu_request(struct corsairpsu_data *priv, u8 cmd, u8 rail, void *data) in corsairpsu_request() argument
211 mutex_lock(&priv->lock); in corsairpsu_request()
219 ret = corsairpsu_usb_cmd(priv, 2, PSU_CMD_SELECT_RAIL, rail, NULL); in corsairpsu_request()
230 mutex_unlock(&priv->lock); in corsairpsu_request()
234 static int corsairpsu_get_value(struct corsairpsu_data *priv, u8 cmd, u8 rail, long *val) in corsairpsu_get_value() argument
240 ret = corsairpsu_request(priv, cmd, rail, data); in corsairpsu_get_value()
277 ret = -EOPNOTSUPP; in corsairpsu_get_value()
287 int rail; in corsairpsu_get_criticals() local
289 for (rail = 0; rail < TEMP_COUNT; ++rail) { in corsairpsu_get_criticals()
290 if (!corsairpsu_get_value(priv, PSU_CMD_TEMP_HCRIT, rail, &tmp)) { in corsairpsu_get_criticals()
291 priv->temp_crit_support |= BIT(rail); in corsairpsu_get_criticals()
292 priv->temp_crit[rail] = tmp; in corsairpsu_get_criticals()
296 for (rail = 0; rail < RAIL_COUNT; ++rail) { in corsairpsu_get_criticals()
297 if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_HCRIT, rail, &tmp)) { in corsairpsu_get_criticals()
298 priv->in_crit_support |= BIT(rail); in corsairpsu_get_criticals()
299 priv->in_crit[rail] = tmp; in corsairpsu_get_criticals()
302 if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS_LCRIT, rail, &tmp)) { in corsairpsu_get_criticals()
303 priv->in_lcrit_support |= BIT(rail); in corsairpsu_get_criticals()
304 priv->in_lcrit[rail] = tmp; in corsairpsu_get_criticals()
307 if (!corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS_HCRIT, rail, &tmp)) { in corsairpsu_get_criticals()
308 priv->curr_crit_support |= BIT(rail); in corsairpsu_get_criticals()
309 priv->curr_crit[rail] = tmp; in corsairpsu_get_criticals()
318 priv->in_curr_cmd_support = !corsairpsu_get_value(priv, PSU_CMD_IN_AMPS, 0, &tmp); in corsairpsu_check_cmd_support()
330 if (channel > 0 && !(priv->temp_crit_support & BIT(channel - 1))) in corsairpsu_hwmon_temp_is_visible()
373 if (channel > 0 && !(priv->in_crit_support & BIT(channel - 1))) in corsairpsu_hwmon_in_is_visible()
377 if (channel > 0 && !(priv->in_lcrit_support & BIT(channel - 1))) in corsairpsu_hwmon_in_is_visible()
394 if (channel == 0 && !priv->in_curr_cmd_support) in corsairpsu_hwmon_curr_is_visible()
399 if (channel > 0 && !(priv->curr_crit_support & BIT(channel - 1))) in corsairpsu_hwmon_curr_is_visible()
433 int err = -EOPNOTSUPP; in corsairpsu_hwmon_temp_read()
440 *val = priv->temp_crit[channel]; in corsairpsu_hwmon_temp_read()
458 return corsairpsu_get_value(priv, PSU_CMD_RAIL_WATTS, channel - 1, val); in corsairpsu_hwmon_power_read()
464 return -EOPNOTSUPP; in corsairpsu_hwmon_power_read()
469 int err = -EOPNOTSUPP; in corsairpsu_hwmon_in_read()
477 return corsairpsu_get_value(priv, PSU_CMD_RAIL_VOLTS, channel - 1, val); in corsairpsu_hwmon_in_read()
483 *val = priv->in_crit[channel - 1]; in corsairpsu_hwmon_in_read()
487 *val = priv->in_lcrit[channel - 1]; in corsairpsu_hwmon_in_read()
498 int err = -EOPNOTSUPP; in corsairpsu_hwmon_curr_read()
506 return corsairpsu_get_value(priv, PSU_CMD_RAIL_AMPS, channel - 1, val); in corsairpsu_hwmon_curr_read()
512 *val = priv->curr_crit[channel - 1]; in corsairpsu_hwmon_curr_read()
533 return -EOPNOTSUPP; in corsairpsu_hwmon_ops_read()
541 return -EOPNOTSUPP; in corsairpsu_hwmon_ops_read()
565 return -EOPNOTSUPP; in corsairpsu_hwmon_ops_read_string()
609 struct corsairpsu_data *priv = seqf->private; in print_uptime()
648 struct corsairpsu_data *priv = seqf->private; in vendor_show()
650 seq_printf(seqf, "%s\n", priv->vendor); in vendor_show()
658 struct corsairpsu_data *priv = seqf->private; in product_show()
660 seq_printf(seqf, "%s\n", priv->product); in product_show()
668 struct corsairpsu_data *priv = seqf->private; in ocpmode_show()
673 * The rail mode is switchable on the fly. The RAW interface can be used for this. But it in ocpmode_show()
677 * than OCP_MULTI_RAIL can be considered as "single rail". in ocpmode_show()
683 seq_printf(seqf, "%s\n", (val == OCP_MULTI_RAIL) ? "multi rail" : "single rail"); in ocpmode_show()
691 char name[32]; in corsairpsu_debugfs_init()
693 scnprintf(name, sizeof(name), "%s-%s", DRIVER_NAME, dev_name(&priv->hdev->dev)); in corsairpsu_debugfs_init()
695 priv->debugfs = debugfs_create_dir(name, NULL); in corsairpsu_debugfs_init()
696 debugfs_create_file("uptime", 0444, priv->debugfs, priv, &uptime_fops); in corsairpsu_debugfs_init()
697 debugfs_create_file("uptime_total", 0444, priv->debugfs, priv, &uptime_total_fops); in corsairpsu_debugfs_init()
698 debugfs_create_file("vendor", 0444, priv->debugfs, priv, &vendor_fops); in corsairpsu_debugfs_init()
699 debugfs_create_file("product", 0444, priv->debugfs, priv, &product_fops); in corsairpsu_debugfs_init()
700 debugfs_create_file("ocpmode", 0444, priv->debugfs, priv, &ocpmode_fops); in corsairpsu_debugfs_init()
716 priv = devm_kzalloc(&hdev->dev, sizeof(struct corsairpsu_data), GFP_KERNEL); in corsairpsu_probe()
718 return -ENOMEM; in corsairpsu_probe()
720 priv->cmd_buffer = devm_kmalloc(&hdev->dev, CMD_BUFFER_SIZE, GFP_KERNEL); in corsairpsu_probe()
721 if (!priv->cmd_buffer) in corsairpsu_probe()
722 return -ENOMEM; in corsairpsu_probe()
736 priv->hdev = hdev; in corsairpsu_probe()
738 mutex_init(&priv->lock); in corsairpsu_probe()
739 init_completion(&priv->wait_completion); in corsairpsu_probe()
745 dev_err(&hdev->dev, "unable to initialize device (%d)\n", ret); in corsairpsu_probe()
751 dev_err(&hdev->dev, "unable to query firmware (%d)\n", ret); in corsairpsu_probe()
758 priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsairpsu", priv, in corsairpsu_probe()
761 if (IS_ERR(priv->hwmon_dev)) { in corsairpsu_probe()
762 ret = PTR_ERR(priv->hwmon_dev); in corsairpsu_probe()
781 debugfs_remove_recursive(priv->debugfs); in corsairpsu_remove()
782 hwmon_device_unregister(priv->hwmon_dev); in corsairpsu_remove()
792 if (completion_done(&priv->wait_completion)) in corsairpsu_raw_event()
795 memcpy(priv->cmd_buffer, data, min(CMD_BUFFER_SIZE, size)); in corsairpsu_raw_event()
796 complete(&priv->wait_completion); in corsairpsu_raw_event()