2 * Copyright 2017 IBM Corp.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
10 #include <linux/bitops.h>
11 #include <linux/debugfs.h>
12 #include <linux/device.h>
14 #include <linux/i2c.h>
15 #include <linux/jiffies.h>
16 #include <linux/leds.h>
17 #include <linux/module.h>
18 #include <linux/mutex.h>
19 #include <linux/pmbus.h>
23 #define CFFPS_FRU_CMD 0x9A
24 #define CFFPS_PN_CMD 0x9B
25 #define CFFPS_SN_CMD 0x9E
26 #define CFFPS_CCIN_CMD 0xBD
27 #define CFFPS_FW_CMD_START 0xFA
28 #define CFFPS_FW_NUM_BYTES 4
29 #define CFFPS_SYS_CONFIG_CMD 0xDA
31 #define CFFPS_INPUT_HISTORY_CMD 0xD6
32 #define CFFPS_INPUT_HISTORY_SIZE 100
34 /* STATUS_MFR_SPECIFIC bits */
35 #define CFFPS_MFR_FAN_FAULT BIT(0)
36 #define CFFPS_MFR_THERMAL_FAULT BIT(1)
37 #define CFFPS_MFR_OV_FAULT BIT(2)
38 #define CFFPS_MFR_UV_FAULT BIT(3)
39 #define CFFPS_MFR_PS_KILL BIT(4)
40 #define CFFPS_MFR_OC_FAULT BIT(5)
41 #define CFFPS_MFR_VAUX_FAULT BIT(6)
42 #define CFFPS_MFR_CURRENT_SHARE_WARNING BIT(7)
44 #define CFFPS_LED_BLINK BIT(0)
45 #define CFFPS_LED_ON BIT(1)
46 #define CFFPS_LED_OFF BIT(2)
47 #define CFFPS_BLINK_RATE_MS 250
50 CFFPS_DEBUGFS_INPUT_HISTORY
= 0,
56 CFFPS_DEBUGFS_NUM_ENTRIES
59 struct ibm_cffps_input_history
{
60 struct mutex update_lock
;
61 unsigned long last_update
;
64 u8 data
[CFFPS_INPUT_HISTORY_SIZE
];
68 struct i2c_client
*client
;
70 struct ibm_cffps_input_history input_history
;
72 int debugfs_entries
[CFFPS_DEBUGFS_NUM_ENTRIES
];
76 struct led_classdev led
;
79 #define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)])
81 static ssize_t
ibm_cffps_read_input_history(struct ibm_cffps
*psu
,
82 char __user
*buf
, size_t count
,
86 u8 msgbuf0
[1] = { CFFPS_INPUT_HISTORY_CMD
};
87 u8 msgbuf1
[CFFPS_INPUT_HISTORY_SIZE
+ 1] = { 0 };
88 struct i2c_msg msg
[2] = {
90 .addr
= psu
->client
->addr
,
91 .flags
= psu
->client
->flags
,
95 .addr
= psu
->client
->addr
,
96 .flags
= psu
->client
->flags
| I2C_M_RD
,
97 .len
= CFFPS_INPUT_HISTORY_SIZE
+ 1,
103 mutex_lock(&psu
->input_history
.update_lock
);
104 if (time_after(jiffies
, psu
->input_history
.last_update
+ HZ
)) {
106 * Use a raw i2c transfer, since we need more bytes
107 * than Linux I2C supports through smbus xfr (only 32).
109 rc
= i2c_transfer(psu
->client
->adapter
, msg
, 2);
111 mutex_unlock(&psu
->input_history
.update_lock
);
115 psu
->input_history
.byte_count
= msgbuf1
[0];
116 memcpy(psu
->input_history
.data
, &msgbuf1
[1],
117 CFFPS_INPUT_HISTORY_SIZE
);
118 psu
->input_history
.last_update
= jiffies
;
121 mutex_unlock(&psu
->input_history
.update_lock
);
124 return simple_read_from_buffer(buf
, count
, ppos
,
125 psu
->input_history
.data
,
126 psu
->input_history
.byte_count
);
129 static ssize_t
ibm_cffps_debugfs_op(struct file
*file
, char __user
*buf
,
130 size_t count
, loff_t
*ppos
)
134 int *idxp
= file
->private_data
;
136 struct ibm_cffps
*psu
= to_psu(idxp
, idx
);
137 char data
[I2C_SMBUS_BLOCK_MAX
] = { 0 };
140 case CFFPS_DEBUGFS_INPUT_HISTORY
:
141 return ibm_cffps_read_input_history(psu
, buf
, count
, ppos
);
142 case CFFPS_DEBUGFS_FRU
:
145 case CFFPS_DEBUGFS_PN
:
148 case CFFPS_DEBUGFS_SN
:
151 case CFFPS_DEBUGFS_CCIN
:
152 rc
= i2c_smbus_read_word_swapped(psu
->client
, CFFPS_CCIN_CMD
);
156 rc
= snprintf(data
, 5, "%04X", rc
);
158 case CFFPS_DEBUGFS_FW
:
159 for (i
= 0; i
< CFFPS_FW_NUM_BYTES
; ++i
) {
160 rc
= i2c_smbus_read_byte_data(psu
->client
,
161 CFFPS_FW_CMD_START
+ i
);
165 snprintf(&data
[i
* 2], 3, "%02X", rc
);
174 rc
= i2c_smbus_read_block_data(psu
->client
, cmd
, data
);
182 return simple_read_from_buffer(buf
, count
, ppos
, data
, rc
);
185 static const struct file_operations ibm_cffps_fops
= {
186 .llseek
= noop_llseek
,
187 .read
= ibm_cffps_debugfs_op
,
191 static int ibm_cffps_read_byte_data(struct i2c_client
*client
, int page
,
197 case PMBUS_STATUS_VOUT
:
198 case PMBUS_STATUS_IOUT
:
199 case PMBUS_STATUS_TEMPERATURE
:
200 case PMBUS_STATUS_FAN_12
:
201 rc
= pmbus_read_byte_data(client
, page
, reg
);
205 mfr
= pmbus_read_byte_data(client
, page
,
206 PMBUS_STATUS_MFR_SPECIFIC
);
209 * Return the status register instead of an error,
210 * since we successfully read status.
214 /* Add MFR_SPECIFIC bits to the standard pmbus status regs. */
215 if (reg
== PMBUS_STATUS_FAN_12
) {
216 if (mfr
& CFFPS_MFR_FAN_FAULT
)
217 rc
|= PB_FAN_FAN1_FAULT
;
218 } else if (reg
== PMBUS_STATUS_TEMPERATURE
) {
219 if (mfr
& CFFPS_MFR_THERMAL_FAULT
)
220 rc
|= PB_TEMP_OT_FAULT
;
221 } else if (reg
== PMBUS_STATUS_VOUT
) {
222 if (mfr
& (CFFPS_MFR_OV_FAULT
| CFFPS_MFR_VAUX_FAULT
))
223 rc
|= PB_VOLTAGE_OV_FAULT
;
224 if (mfr
& CFFPS_MFR_UV_FAULT
)
225 rc
|= PB_VOLTAGE_UV_FAULT
;
226 } else if (reg
== PMBUS_STATUS_IOUT
) {
227 if (mfr
& CFFPS_MFR_OC_FAULT
)
228 rc
|= PB_IOUT_OC_FAULT
;
229 if (mfr
& CFFPS_MFR_CURRENT_SHARE_WARNING
)
230 rc
|= PB_CURRENT_SHARE_FAULT
;
241 static int ibm_cffps_read_word_data(struct i2c_client
*client
, int page
,
247 case PMBUS_STATUS_WORD
:
248 rc
= pmbus_read_word_data(client
, page
, reg
);
252 mfr
= pmbus_read_byte_data(client
, page
,
253 PMBUS_STATUS_MFR_SPECIFIC
);
256 * Return the status register instead of an error,
257 * since we successfully read status.
261 if (mfr
& CFFPS_MFR_PS_KILL
)
272 static void ibm_cffps_led_brightness_set(struct led_classdev
*led_cdev
,
273 enum led_brightness brightness
)
276 struct ibm_cffps
*psu
= container_of(led_cdev
, struct ibm_cffps
, led
);
278 if (brightness
== LED_OFF
) {
279 psu
->led_state
= CFFPS_LED_OFF
;
281 brightness
= LED_FULL
;
282 if (psu
->led_state
!= CFFPS_LED_BLINK
)
283 psu
->led_state
= CFFPS_LED_ON
;
286 rc
= i2c_smbus_write_byte_data(psu
->client
, CFFPS_SYS_CONFIG_CMD
,
291 led_cdev
->brightness
= brightness
;
294 static int ibm_cffps_led_blink_set(struct led_classdev
*led_cdev
,
295 unsigned long *delay_on
,
296 unsigned long *delay_off
)
299 struct ibm_cffps
*psu
= container_of(led_cdev
, struct ibm_cffps
, led
);
301 psu
->led_state
= CFFPS_LED_BLINK
;
303 if (led_cdev
->brightness
== LED_OFF
)
306 rc
= i2c_smbus_write_byte_data(psu
->client
, CFFPS_SYS_CONFIG_CMD
,
311 *delay_on
= CFFPS_BLINK_RATE_MS
;
312 *delay_off
= CFFPS_BLINK_RATE_MS
;
317 static void ibm_cffps_create_led_class(struct ibm_cffps
*psu
)
320 struct i2c_client
*client
= psu
->client
;
321 struct device
*dev
= &client
->dev
;
323 snprintf(psu
->led_name
, sizeof(psu
->led_name
), "%s-%02x", client
->name
,
325 psu
->led
.name
= psu
->led_name
;
326 psu
->led
.max_brightness
= LED_FULL
;
327 psu
->led
.brightness_set
= ibm_cffps_led_brightness_set
;
328 psu
->led
.blink_set
= ibm_cffps_led_blink_set
;
330 rc
= devm_led_classdev_register(dev
, &psu
->led
);
332 dev_warn(dev
, "failed to register led class: %d\n", rc
);
335 static struct pmbus_driver_info ibm_cffps_info
= {
337 .func
[0] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT
| PMBUS_HAVE_IOUT
|
338 PMBUS_HAVE_PIN
| PMBUS_HAVE_FAN12
| PMBUS_HAVE_TEMP
|
339 PMBUS_HAVE_TEMP2
| PMBUS_HAVE_TEMP3
| PMBUS_HAVE_STATUS_VOUT
|
340 PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_INPUT
|
341 PMBUS_HAVE_STATUS_TEMP
| PMBUS_HAVE_STATUS_FAN12
,
342 .read_byte_data
= ibm_cffps_read_byte_data
,
343 .read_word_data
= ibm_cffps_read_word_data
,
346 static struct pmbus_platform_data ibm_cffps_pdata
= {
347 .flags
= PMBUS_SKIP_STATUS_CHECK
,
350 static int ibm_cffps_probe(struct i2c_client
*client
,
351 const struct i2c_device_id
*id
)
354 struct dentry
*debugfs
;
355 struct dentry
*ibm_cffps_dir
;
356 struct ibm_cffps
*psu
;
358 client
->dev
.platform_data
= &ibm_cffps_pdata
;
359 rc
= pmbus_do_probe(client
, id
, &ibm_cffps_info
);
364 * Don't fail the probe if there isn't enough memory for leds and
367 psu
= devm_kzalloc(&client
->dev
, sizeof(*psu
), GFP_KERNEL
);
371 psu
->client
= client
;
372 mutex_init(&psu
->input_history
.update_lock
);
373 psu
->input_history
.last_update
= jiffies
- HZ
;
375 ibm_cffps_create_led_class(psu
);
377 /* Don't fail the probe if we can't create debugfs */
378 debugfs
= pmbus_get_debugfs_dir(client
);
382 ibm_cffps_dir
= debugfs_create_dir(client
->name
, debugfs
);
386 for (i
= 0; i
< CFFPS_DEBUGFS_NUM_ENTRIES
; ++i
)
387 psu
->debugfs_entries
[i
] = i
;
389 debugfs_create_file("input_history", 0444, ibm_cffps_dir
,
390 &psu
->debugfs_entries
[CFFPS_DEBUGFS_INPUT_HISTORY
],
392 debugfs_create_file("fru", 0444, ibm_cffps_dir
,
393 &psu
->debugfs_entries
[CFFPS_DEBUGFS_FRU
],
395 debugfs_create_file("part_number", 0444, ibm_cffps_dir
,
396 &psu
->debugfs_entries
[CFFPS_DEBUGFS_PN
],
398 debugfs_create_file("serial_number", 0444, ibm_cffps_dir
,
399 &psu
->debugfs_entries
[CFFPS_DEBUGFS_SN
],
401 debugfs_create_file("ccin", 0444, ibm_cffps_dir
,
402 &psu
->debugfs_entries
[CFFPS_DEBUGFS_CCIN
],
404 debugfs_create_file("fw_version", 0444, ibm_cffps_dir
,
405 &psu
->debugfs_entries
[CFFPS_DEBUGFS_FW
],
411 static const struct i2c_device_id ibm_cffps_id
[] = {
415 MODULE_DEVICE_TABLE(i2c
, ibm_cffps_id
);
417 static const struct of_device_id ibm_cffps_of_match
[] = {
418 { .compatible
= "ibm,cffps1" },
421 MODULE_DEVICE_TABLE(of
, ibm_cffps_of_match
);
423 static struct i2c_driver ibm_cffps_driver
= {
426 .of_match_table
= ibm_cffps_of_match
,
428 .probe
= ibm_cffps_probe
,
429 .remove
= pmbus_do_remove
,
430 .id_table
= ibm_cffps_id
,
433 module_i2c_driver(ibm_cffps_driver
);
435 MODULE_AUTHOR("Eddie James");
436 MODULE_DESCRIPTION("PMBus driver for IBM Common Form Factor power supplies");
437 MODULE_LICENSE("GPL");