1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright 2017 IBM Corp.
6 #include <linux/bitops.h>
7 #include <linux/debugfs.h>
8 #include <linux/device.h>
10 #include <linux/i2c.h>
11 #include <linux/jiffies.h>
12 #include <linux/leds.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/pmbus.h>
19 #define CFFPS_FRU_CMD 0x9A
20 #define CFFPS_PN_CMD 0x9B
21 #define CFFPS_SN_CMD 0x9E
22 #define CFFPS_CCIN_CMD 0xBD
23 #define CFFPS_FW_CMD_START 0xFA
24 #define CFFPS_FW_NUM_BYTES 4
25 #define CFFPS_SYS_CONFIG_CMD 0xDA
27 #define CFFPS_INPUT_HISTORY_CMD 0xD6
28 #define CFFPS_INPUT_HISTORY_SIZE 100
30 /* STATUS_MFR_SPECIFIC bits */
31 #define CFFPS_MFR_FAN_FAULT BIT(0)
32 #define CFFPS_MFR_THERMAL_FAULT BIT(1)
33 #define CFFPS_MFR_OV_FAULT BIT(2)
34 #define CFFPS_MFR_UV_FAULT BIT(3)
35 #define CFFPS_MFR_PS_KILL BIT(4)
36 #define CFFPS_MFR_OC_FAULT BIT(5)
37 #define CFFPS_MFR_VAUX_FAULT BIT(6)
38 #define CFFPS_MFR_CURRENT_SHARE_WARNING BIT(7)
40 #define CFFPS_LED_BLINK BIT(0)
41 #define CFFPS_LED_ON BIT(1)
42 #define CFFPS_LED_OFF BIT(2)
43 #define CFFPS_BLINK_RATE_MS 250
46 CFFPS_DEBUGFS_INPUT_HISTORY
= 0,
52 CFFPS_DEBUGFS_NUM_ENTRIES
55 struct ibm_cffps_input_history
{
56 struct mutex update_lock
;
57 unsigned long last_update
;
60 u8 data
[CFFPS_INPUT_HISTORY_SIZE
];
64 struct i2c_client
*client
;
66 struct ibm_cffps_input_history input_history
;
68 int debugfs_entries
[CFFPS_DEBUGFS_NUM_ENTRIES
];
72 struct led_classdev led
;
75 #define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)])
77 static ssize_t
ibm_cffps_read_input_history(struct ibm_cffps
*psu
,
78 char __user
*buf
, size_t count
,
82 u8 msgbuf0
[1] = { CFFPS_INPUT_HISTORY_CMD
};
83 u8 msgbuf1
[CFFPS_INPUT_HISTORY_SIZE
+ 1] = { 0 };
84 struct i2c_msg msg
[2] = {
86 .addr
= psu
->client
->addr
,
87 .flags
= psu
->client
->flags
,
91 .addr
= psu
->client
->addr
,
92 .flags
= psu
->client
->flags
| I2C_M_RD
,
93 .len
= CFFPS_INPUT_HISTORY_SIZE
+ 1,
99 mutex_lock(&psu
->input_history
.update_lock
);
100 if (time_after(jiffies
, psu
->input_history
.last_update
+ HZ
)) {
102 * Use a raw i2c transfer, since we need more bytes
103 * than Linux I2C supports through smbus xfr (only 32).
105 rc
= i2c_transfer(psu
->client
->adapter
, msg
, 2);
107 mutex_unlock(&psu
->input_history
.update_lock
);
111 psu
->input_history
.byte_count
= msgbuf1
[0];
112 memcpy(psu
->input_history
.data
, &msgbuf1
[1],
113 CFFPS_INPUT_HISTORY_SIZE
);
114 psu
->input_history
.last_update
= jiffies
;
117 mutex_unlock(&psu
->input_history
.update_lock
);
120 return simple_read_from_buffer(buf
, count
, ppos
,
121 psu
->input_history
.data
,
122 psu
->input_history
.byte_count
);
125 static ssize_t
ibm_cffps_debugfs_op(struct file
*file
, char __user
*buf
,
126 size_t count
, loff_t
*ppos
)
130 int *idxp
= file
->private_data
;
132 struct ibm_cffps
*psu
= to_psu(idxp
, idx
);
133 char data
[I2C_SMBUS_BLOCK_MAX
] = { 0 };
136 case CFFPS_DEBUGFS_INPUT_HISTORY
:
137 return ibm_cffps_read_input_history(psu
, buf
, count
, ppos
);
138 case CFFPS_DEBUGFS_FRU
:
141 case CFFPS_DEBUGFS_PN
:
144 case CFFPS_DEBUGFS_SN
:
147 case CFFPS_DEBUGFS_CCIN
:
148 rc
= i2c_smbus_read_word_swapped(psu
->client
, CFFPS_CCIN_CMD
);
152 rc
= snprintf(data
, 5, "%04X", rc
);
154 case CFFPS_DEBUGFS_FW
:
155 for (i
= 0; i
< CFFPS_FW_NUM_BYTES
; ++i
) {
156 rc
= i2c_smbus_read_byte_data(psu
->client
,
157 CFFPS_FW_CMD_START
+ i
);
161 snprintf(&data
[i
* 2], 3, "%02X", rc
);
170 rc
= i2c_smbus_read_block_data(psu
->client
, cmd
, data
);
178 return simple_read_from_buffer(buf
, count
, ppos
, data
, rc
);
181 static const struct file_operations ibm_cffps_fops
= {
182 .llseek
= noop_llseek
,
183 .read
= ibm_cffps_debugfs_op
,
187 static int ibm_cffps_read_byte_data(struct i2c_client
*client
, int page
,
193 case PMBUS_STATUS_VOUT
:
194 case PMBUS_STATUS_IOUT
:
195 case PMBUS_STATUS_TEMPERATURE
:
196 case PMBUS_STATUS_FAN_12
:
197 rc
= pmbus_read_byte_data(client
, page
, reg
);
201 mfr
= pmbus_read_byte_data(client
, page
,
202 PMBUS_STATUS_MFR_SPECIFIC
);
205 * Return the status register instead of an error,
206 * since we successfully read status.
210 /* Add MFR_SPECIFIC bits to the standard pmbus status regs. */
211 if (reg
== PMBUS_STATUS_FAN_12
) {
212 if (mfr
& CFFPS_MFR_FAN_FAULT
)
213 rc
|= PB_FAN_FAN1_FAULT
;
214 } else if (reg
== PMBUS_STATUS_TEMPERATURE
) {
215 if (mfr
& CFFPS_MFR_THERMAL_FAULT
)
216 rc
|= PB_TEMP_OT_FAULT
;
217 } else if (reg
== PMBUS_STATUS_VOUT
) {
218 if (mfr
& (CFFPS_MFR_OV_FAULT
| CFFPS_MFR_VAUX_FAULT
))
219 rc
|= PB_VOLTAGE_OV_FAULT
;
220 if (mfr
& CFFPS_MFR_UV_FAULT
)
221 rc
|= PB_VOLTAGE_UV_FAULT
;
222 } else if (reg
== PMBUS_STATUS_IOUT
) {
223 if (mfr
& CFFPS_MFR_OC_FAULT
)
224 rc
|= PB_IOUT_OC_FAULT
;
225 if (mfr
& CFFPS_MFR_CURRENT_SHARE_WARNING
)
226 rc
|= PB_CURRENT_SHARE_FAULT
;
237 static int ibm_cffps_read_word_data(struct i2c_client
*client
, int page
,
243 case PMBUS_STATUS_WORD
:
244 rc
= pmbus_read_word_data(client
, page
, reg
);
248 mfr
= pmbus_read_byte_data(client
, page
,
249 PMBUS_STATUS_MFR_SPECIFIC
);
252 * Return the status register instead of an error,
253 * since we successfully read status.
257 if (mfr
& CFFPS_MFR_PS_KILL
)
268 static void ibm_cffps_led_brightness_set(struct led_classdev
*led_cdev
,
269 enum led_brightness brightness
)
272 struct ibm_cffps
*psu
= container_of(led_cdev
, struct ibm_cffps
, led
);
274 if (brightness
== LED_OFF
) {
275 psu
->led_state
= CFFPS_LED_OFF
;
277 brightness
= LED_FULL
;
278 if (psu
->led_state
!= CFFPS_LED_BLINK
)
279 psu
->led_state
= CFFPS_LED_ON
;
282 rc
= i2c_smbus_write_byte_data(psu
->client
, CFFPS_SYS_CONFIG_CMD
,
287 led_cdev
->brightness
= brightness
;
290 static int ibm_cffps_led_blink_set(struct led_classdev
*led_cdev
,
291 unsigned long *delay_on
,
292 unsigned long *delay_off
)
295 struct ibm_cffps
*psu
= container_of(led_cdev
, struct ibm_cffps
, led
);
297 psu
->led_state
= CFFPS_LED_BLINK
;
299 if (led_cdev
->brightness
== LED_OFF
)
302 rc
= i2c_smbus_write_byte_data(psu
->client
, CFFPS_SYS_CONFIG_CMD
,
307 *delay_on
= CFFPS_BLINK_RATE_MS
;
308 *delay_off
= CFFPS_BLINK_RATE_MS
;
313 static void ibm_cffps_create_led_class(struct ibm_cffps
*psu
)
316 struct i2c_client
*client
= psu
->client
;
317 struct device
*dev
= &client
->dev
;
319 snprintf(psu
->led_name
, sizeof(psu
->led_name
), "%s-%02x", client
->name
,
321 psu
->led
.name
= psu
->led_name
;
322 psu
->led
.max_brightness
= LED_FULL
;
323 psu
->led
.brightness_set
= ibm_cffps_led_brightness_set
;
324 psu
->led
.blink_set
= ibm_cffps_led_blink_set
;
326 rc
= devm_led_classdev_register(dev
, &psu
->led
);
328 dev_warn(dev
, "failed to register led class: %d\n", rc
);
331 static struct pmbus_driver_info ibm_cffps_info
= {
333 .func
[0] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT
| PMBUS_HAVE_IOUT
|
334 PMBUS_HAVE_PIN
| PMBUS_HAVE_FAN12
| PMBUS_HAVE_TEMP
|
335 PMBUS_HAVE_TEMP2
| PMBUS_HAVE_TEMP3
| PMBUS_HAVE_STATUS_VOUT
|
336 PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_INPUT
|
337 PMBUS_HAVE_STATUS_TEMP
| PMBUS_HAVE_STATUS_FAN12
,
338 .read_byte_data
= ibm_cffps_read_byte_data
,
339 .read_word_data
= ibm_cffps_read_word_data
,
342 static struct pmbus_platform_data ibm_cffps_pdata
= {
343 .flags
= PMBUS_SKIP_STATUS_CHECK
,
346 static int ibm_cffps_probe(struct i2c_client
*client
,
347 const struct i2c_device_id
*id
)
350 struct dentry
*debugfs
;
351 struct dentry
*ibm_cffps_dir
;
352 struct ibm_cffps
*psu
;
354 client
->dev
.platform_data
= &ibm_cffps_pdata
;
355 rc
= pmbus_do_probe(client
, id
, &ibm_cffps_info
);
360 * Don't fail the probe if there isn't enough memory for leds and
363 psu
= devm_kzalloc(&client
->dev
, sizeof(*psu
), GFP_KERNEL
);
367 psu
->client
= client
;
368 mutex_init(&psu
->input_history
.update_lock
);
369 psu
->input_history
.last_update
= jiffies
- HZ
;
371 ibm_cffps_create_led_class(psu
);
373 /* Don't fail the probe if we can't create debugfs */
374 debugfs
= pmbus_get_debugfs_dir(client
);
378 ibm_cffps_dir
= debugfs_create_dir(client
->name
, debugfs
);
382 for (i
= 0; i
< CFFPS_DEBUGFS_NUM_ENTRIES
; ++i
)
383 psu
->debugfs_entries
[i
] = i
;
385 debugfs_create_file("input_history", 0444, ibm_cffps_dir
,
386 &psu
->debugfs_entries
[CFFPS_DEBUGFS_INPUT_HISTORY
],
388 debugfs_create_file("fru", 0444, ibm_cffps_dir
,
389 &psu
->debugfs_entries
[CFFPS_DEBUGFS_FRU
],
391 debugfs_create_file("part_number", 0444, ibm_cffps_dir
,
392 &psu
->debugfs_entries
[CFFPS_DEBUGFS_PN
],
394 debugfs_create_file("serial_number", 0444, ibm_cffps_dir
,
395 &psu
->debugfs_entries
[CFFPS_DEBUGFS_SN
],
397 debugfs_create_file("ccin", 0444, ibm_cffps_dir
,
398 &psu
->debugfs_entries
[CFFPS_DEBUGFS_CCIN
],
400 debugfs_create_file("fw_version", 0444, ibm_cffps_dir
,
401 &psu
->debugfs_entries
[CFFPS_DEBUGFS_FW
],
407 static const struct i2c_device_id ibm_cffps_id
[] = {
411 MODULE_DEVICE_TABLE(i2c
, ibm_cffps_id
);
413 static const struct of_device_id ibm_cffps_of_match
[] = {
414 { .compatible
= "ibm,cffps1" },
417 MODULE_DEVICE_TABLE(of
, ibm_cffps_of_match
);
419 static struct i2c_driver ibm_cffps_driver
= {
422 .of_match_table
= ibm_cffps_of_match
,
424 .probe
= ibm_cffps_probe
,
425 .remove
= pmbus_do_remove
,
426 .id_table
= ibm_cffps_id
,
429 module_i2c_driver(ibm_cffps_driver
);
431 MODULE_AUTHOR("Eddie James");
432 MODULE_DESCRIPTION("PMBus driver for IBM Common Form Factor power supplies");
433 MODULE_LICENSE("GPL");