1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright 2017 IBM Corp.
6 #include <linux/bitfield.h>
7 #include <linux/bitops.h>
8 #include <linux/debugfs.h>
9 #include <linux/device.h>
11 #include <linux/i2c.h>
12 #include <linux/jiffies.h>
13 #include <linux/leds.h>
14 #include <linux/module.h>
15 #include <linux/mutex.h>
16 #include <linux/of_device.h>
17 #include <linux/pmbus.h>
21 #define CFFPS_FRU_CMD 0x9A
22 #define CFFPS_PN_CMD 0x9B
23 #define CFFPS_HEADER_CMD 0x9C
24 #define CFFPS_SN_CMD 0x9E
25 #define CFFPS_MAX_POWER_OUT_CMD 0xA7
26 #define CFFPS_CCIN_CMD 0xBD
27 #define CFFPS_FW_CMD 0xFA
28 #define CFFPS1_FW_NUM_BYTES 4
29 #define CFFPS2_FW_NUM_WORDS 3
30 #define CFFPS_SYS_CONFIG_CMD 0xDA
31 #define CFFPS_12VCS_VOUT_CMD 0xDE
33 #define CFFPS_INPUT_HISTORY_CMD 0xD6
34 #define CFFPS_INPUT_HISTORY_SIZE 100
36 #define CFFPS_CCIN_VERSION GENMASK(15, 8)
37 #define CFFPS_CCIN_VERSION_1 0x2b
38 #define CFFPS_CCIN_VERSION_2 0x2e
40 /* STATUS_MFR_SPECIFIC bits */
41 #define CFFPS_MFR_FAN_FAULT BIT(0)
42 #define CFFPS_MFR_THERMAL_FAULT BIT(1)
43 #define CFFPS_MFR_OV_FAULT BIT(2)
44 #define CFFPS_MFR_UV_FAULT BIT(3)
45 #define CFFPS_MFR_PS_KILL BIT(4)
46 #define CFFPS_MFR_OC_FAULT BIT(5)
47 #define CFFPS_MFR_VAUX_FAULT BIT(6)
48 #define CFFPS_MFR_CURRENT_SHARE_WARNING BIT(7)
50 #define CFFPS_LED_BLINK BIT(0)
51 #define CFFPS_LED_ON BIT(1)
52 #define CFFPS_LED_OFF BIT(2)
53 #define CFFPS_BLINK_RATE_MS 250
56 CFFPS_DEBUGFS_INPUT_HISTORY
= 0,
61 CFFPS_DEBUGFS_MAX_POWER_OUT
,
64 CFFPS_DEBUGFS_ON_OFF_CONFIG
,
65 CFFPS_DEBUGFS_NUM_ENTRIES
68 enum versions
{ cffps1
, cffps2
, cffps_unknown
};
70 struct ibm_cffps_input_history
{
71 struct mutex update_lock
;
72 unsigned long last_update
;
75 u8 data
[CFFPS_INPUT_HISTORY_SIZE
];
79 enum versions version
;
80 struct i2c_client
*client
;
82 struct ibm_cffps_input_history input_history
;
84 int debugfs_entries
[CFFPS_DEBUGFS_NUM_ENTRIES
];
88 struct led_classdev led
;
91 #define to_psu(x, y) container_of((x), struct ibm_cffps, debugfs_entries[(y)])
93 static ssize_t
ibm_cffps_read_input_history(struct ibm_cffps
*psu
,
94 char __user
*buf
, size_t count
,
98 u8 msgbuf0
[1] = { CFFPS_INPUT_HISTORY_CMD
};
99 u8 msgbuf1
[CFFPS_INPUT_HISTORY_SIZE
+ 1] = { 0 };
100 struct i2c_msg msg
[2] = {
102 .addr
= psu
->client
->addr
,
103 .flags
= psu
->client
->flags
,
107 .addr
= psu
->client
->addr
,
108 .flags
= psu
->client
->flags
| I2C_M_RD
,
109 .len
= CFFPS_INPUT_HISTORY_SIZE
+ 1,
115 mutex_lock(&psu
->input_history
.update_lock
);
116 if (time_after(jiffies
, psu
->input_history
.last_update
+ HZ
)) {
118 * Use a raw i2c transfer, since we need more bytes
119 * than Linux I2C supports through smbus xfr (only 32).
121 rc
= i2c_transfer(psu
->client
->adapter
, msg
, 2);
123 mutex_unlock(&psu
->input_history
.update_lock
);
127 psu
->input_history
.byte_count
= msgbuf1
[0];
128 memcpy(psu
->input_history
.data
, &msgbuf1
[1],
129 CFFPS_INPUT_HISTORY_SIZE
);
130 psu
->input_history
.last_update
= jiffies
;
133 mutex_unlock(&psu
->input_history
.update_lock
);
136 return simple_read_from_buffer(buf
, count
, ppos
,
137 psu
->input_history
.data
,
138 psu
->input_history
.byte_count
);
141 static ssize_t
ibm_cffps_debugfs_read(struct file
*file
, char __user
*buf
,
142 size_t count
, loff_t
*ppos
)
146 int *idxp
= file
->private_data
;
148 struct ibm_cffps
*psu
= to_psu(idxp
, idx
);
149 char data
[I2C_SMBUS_BLOCK_MAX
+ 2] = { 0 };
151 pmbus_set_page(psu
->client
, 0);
154 case CFFPS_DEBUGFS_INPUT_HISTORY
:
155 return ibm_cffps_read_input_history(psu
, buf
, count
, ppos
);
156 case CFFPS_DEBUGFS_FRU
:
159 case CFFPS_DEBUGFS_PN
:
162 case CFFPS_DEBUGFS_HEADER
:
163 cmd
= CFFPS_HEADER_CMD
;
165 case CFFPS_DEBUGFS_SN
:
168 case CFFPS_DEBUGFS_MAX_POWER_OUT
:
169 rc
= i2c_smbus_read_word_swapped(psu
->client
,
170 CFFPS_MAX_POWER_OUT_CMD
);
174 rc
= snprintf(data
, I2C_SMBUS_BLOCK_MAX
, "%d", rc
);
176 case CFFPS_DEBUGFS_CCIN
:
177 rc
= i2c_smbus_read_word_swapped(psu
->client
, CFFPS_CCIN_CMD
);
181 rc
= snprintf(data
, 5, "%04X", rc
);
183 case CFFPS_DEBUGFS_FW
:
184 switch (psu
->version
) {
186 for (i
= 0; i
< CFFPS1_FW_NUM_BYTES
; ++i
) {
187 rc
= i2c_smbus_read_byte_data(psu
->client
,
193 snprintf(&data
[i
* 2], 3, "%02X", rc
);
199 for (i
= 0; i
< CFFPS2_FW_NUM_WORDS
; ++i
) {
200 rc
= i2c_smbus_read_word_data(psu
->client
,
206 snprintf(&data
[i
* 4], 5, "%04X", rc
);
215 case CFFPS_DEBUGFS_ON_OFF_CONFIG
:
216 rc
= i2c_smbus_read_byte_data(psu
->client
,
217 PMBUS_ON_OFF_CONFIG
);
221 rc
= snprintf(data
, 3, "%02x", rc
);
227 rc
= i2c_smbus_read_block_data(psu
->client
, cmd
, data
);
235 return simple_read_from_buffer(buf
, count
, ppos
, data
, rc
);
238 static ssize_t
ibm_cffps_debugfs_write(struct file
*file
,
239 const char __user
*buf
, size_t count
,
244 int *idxp
= file
->private_data
;
246 struct ibm_cffps
*psu
= to_psu(idxp
, idx
);
249 case CFFPS_DEBUGFS_ON_OFF_CONFIG
:
250 pmbus_set_page(psu
->client
, 0);
252 rc
= simple_write_to_buffer(&data
, 1, ppos
, buf
, count
);
256 rc
= i2c_smbus_write_byte_data(psu
->client
,
257 PMBUS_ON_OFF_CONFIG
, data
);
270 static const struct file_operations ibm_cffps_fops
= {
271 .llseek
= noop_llseek
,
272 .read
= ibm_cffps_debugfs_read
,
273 .write
= ibm_cffps_debugfs_write
,
277 static int ibm_cffps_read_byte_data(struct i2c_client
*client
, int page
,
283 case PMBUS_STATUS_VOUT
:
284 case PMBUS_STATUS_IOUT
:
285 case PMBUS_STATUS_TEMPERATURE
:
286 case PMBUS_STATUS_FAN_12
:
287 rc
= pmbus_read_byte_data(client
, page
, reg
);
291 mfr
= pmbus_read_byte_data(client
, page
,
292 PMBUS_STATUS_MFR_SPECIFIC
);
295 * Return the status register instead of an error,
296 * since we successfully read status.
300 /* Add MFR_SPECIFIC bits to the standard pmbus status regs. */
301 if (reg
== PMBUS_STATUS_FAN_12
) {
302 if (mfr
& CFFPS_MFR_FAN_FAULT
)
303 rc
|= PB_FAN_FAN1_FAULT
;
304 } else if (reg
== PMBUS_STATUS_TEMPERATURE
) {
305 if (mfr
& CFFPS_MFR_THERMAL_FAULT
)
306 rc
|= PB_TEMP_OT_FAULT
;
307 } else if (reg
== PMBUS_STATUS_VOUT
) {
308 if (mfr
& (CFFPS_MFR_OV_FAULT
| CFFPS_MFR_VAUX_FAULT
))
309 rc
|= PB_VOLTAGE_OV_FAULT
;
310 if (mfr
& CFFPS_MFR_UV_FAULT
)
311 rc
|= PB_VOLTAGE_UV_FAULT
;
312 } else if (reg
== PMBUS_STATUS_IOUT
) {
313 if (mfr
& CFFPS_MFR_OC_FAULT
)
314 rc
|= PB_IOUT_OC_FAULT
;
315 if (mfr
& CFFPS_MFR_CURRENT_SHARE_WARNING
)
316 rc
|= PB_CURRENT_SHARE_FAULT
;
327 static int ibm_cffps_read_word_data(struct i2c_client
*client
, int page
,
333 case PMBUS_STATUS_WORD
:
334 rc
= pmbus_read_word_data(client
, page
, reg
);
338 mfr
= pmbus_read_byte_data(client
, page
,
339 PMBUS_STATUS_MFR_SPECIFIC
);
342 * Return the status register instead of an error,
343 * since we successfully read status.
347 if (mfr
& CFFPS_MFR_PS_KILL
)
350 case PMBUS_VIRT_READ_VMON
:
351 rc
= pmbus_read_word_data(client
, page
, CFFPS_12VCS_VOUT_CMD
);
361 static int ibm_cffps_led_brightness_set(struct led_classdev
*led_cdev
,
362 enum led_brightness brightness
)
366 struct ibm_cffps
*psu
= container_of(led_cdev
, struct ibm_cffps
, led
);
368 if (brightness
== LED_OFF
) {
369 next_led_state
= CFFPS_LED_OFF
;
371 brightness
= LED_FULL
;
373 if (psu
->led_state
!= CFFPS_LED_BLINK
)
374 next_led_state
= CFFPS_LED_ON
;
376 next_led_state
= CFFPS_LED_BLINK
;
379 dev_dbg(&psu
->client
->dev
, "LED brightness set: %d. Command: %d.\n",
380 brightness
, next_led_state
);
382 pmbus_set_page(psu
->client
, 0);
384 rc
= i2c_smbus_write_byte_data(psu
->client
, CFFPS_SYS_CONFIG_CMD
,
389 psu
->led_state
= next_led_state
;
390 led_cdev
->brightness
= brightness
;
395 static int ibm_cffps_led_blink_set(struct led_classdev
*led_cdev
,
396 unsigned long *delay_on
,
397 unsigned long *delay_off
)
400 struct ibm_cffps
*psu
= container_of(led_cdev
, struct ibm_cffps
, led
);
402 dev_dbg(&psu
->client
->dev
, "LED blink set.\n");
404 pmbus_set_page(psu
->client
, 0);
406 rc
= i2c_smbus_write_byte_data(psu
->client
, CFFPS_SYS_CONFIG_CMD
,
411 psu
->led_state
= CFFPS_LED_BLINK
;
412 led_cdev
->brightness
= LED_FULL
;
413 *delay_on
= CFFPS_BLINK_RATE_MS
;
414 *delay_off
= CFFPS_BLINK_RATE_MS
;
419 static void ibm_cffps_create_led_class(struct ibm_cffps
*psu
)
422 struct i2c_client
*client
= psu
->client
;
423 struct device
*dev
= &client
->dev
;
425 snprintf(psu
->led_name
, sizeof(psu
->led_name
), "%s-%02x", client
->name
,
427 psu
->led
.name
= psu
->led_name
;
428 psu
->led
.max_brightness
= LED_FULL
;
429 psu
->led
.brightness_set_blocking
= ibm_cffps_led_brightness_set
;
430 psu
->led
.blink_set
= ibm_cffps_led_blink_set
;
432 rc
= devm_led_classdev_register(dev
, &psu
->led
);
434 dev_warn(dev
, "failed to register led class: %d\n", rc
);
436 i2c_smbus_write_byte_data(client
, CFFPS_SYS_CONFIG_CMD
,
440 static struct pmbus_driver_info ibm_cffps_info
[] = {
443 .func
[0] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT
| PMBUS_HAVE_IOUT
|
444 PMBUS_HAVE_PIN
| PMBUS_HAVE_FAN12
| PMBUS_HAVE_TEMP
|
445 PMBUS_HAVE_TEMP2
| PMBUS_HAVE_TEMP3
|
446 PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_STATUS_IOUT
|
447 PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_STATUS_TEMP
|
448 PMBUS_HAVE_STATUS_FAN12
,
449 .read_byte_data
= ibm_cffps_read_byte_data
,
450 .read_word_data
= ibm_cffps_read_word_data
,
454 .func
[0] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT
| PMBUS_HAVE_IOUT
|
455 PMBUS_HAVE_PIN
| PMBUS_HAVE_FAN12
| PMBUS_HAVE_TEMP
|
456 PMBUS_HAVE_TEMP2
| PMBUS_HAVE_TEMP3
|
457 PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_STATUS_IOUT
|
458 PMBUS_HAVE_STATUS_INPUT
| PMBUS_HAVE_STATUS_TEMP
|
459 PMBUS_HAVE_STATUS_FAN12
| PMBUS_HAVE_VMON
,
460 .func
[1] = PMBUS_HAVE_VOUT
| PMBUS_HAVE_IOUT
|
461 PMBUS_HAVE_TEMP
| PMBUS_HAVE_TEMP2
| PMBUS_HAVE_TEMP3
|
462 PMBUS_HAVE_STATUS_VOUT
| PMBUS_HAVE_STATUS_IOUT
,
463 .read_byte_data
= ibm_cffps_read_byte_data
,
464 .read_word_data
= ibm_cffps_read_word_data
,
468 static struct pmbus_platform_data ibm_cffps_pdata
= {
469 .flags
= PMBUS_SKIP_STATUS_CHECK
,
472 static int ibm_cffps_probe(struct i2c_client
*client
,
473 const struct i2c_device_id
*id
)
476 enum versions vs
= cffps_unknown
;
477 struct dentry
*debugfs
;
478 struct dentry
*ibm_cffps_dir
;
479 struct ibm_cffps
*psu
;
480 const void *md
= of_device_get_match_data(&client
->dev
);
483 vs
= (enum versions
)md
;
485 vs
= (enum versions
)id
->driver_data
;
487 if (vs
== cffps_unknown
) {
488 u16 ccin_version
= CFFPS_CCIN_VERSION_1
;
489 int ccin
= i2c_smbus_read_word_swapped(client
, CFFPS_CCIN_CMD
);
492 ccin_version
= FIELD_GET(CFFPS_CCIN_VERSION
, ccin
);
494 switch (ccin_version
) {
496 case CFFPS_CCIN_VERSION_1
:
499 case CFFPS_CCIN_VERSION_2
:
504 /* Set the client name to include the version number. */
505 snprintf(client
->name
, I2C_NAME_SIZE
, "cffps%d", vs
+ 1);
508 client
->dev
.platform_data
= &ibm_cffps_pdata
;
509 rc
= pmbus_do_probe(client
, id
, &ibm_cffps_info
[vs
]);
514 * Don't fail the probe if there isn't enough memory for leds and
517 psu
= devm_kzalloc(&client
->dev
, sizeof(*psu
), GFP_KERNEL
);
522 psu
->client
= client
;
523 mutex_init(&psu
->input_history
.update_lock
);
524 psu
->input_history
.last_update
= jiffies
- HZ
;
526 ibm_cffps_create_led_class(psu
);
528 /* Don't fail the probe if we can't create debugfs */
529 debugfs
= pmbus_get_debugfs_dir(client
);
533 ibm_cffps_dir
= debugfs_create_dir(client
->name
, debugfs
);
537 for (i
= 0; i
< CFFPS_DEBUGFS_NUM_ENTRIES
; ++i
)
538 psu
->debugfs_entries
[i
] = i
;
540 debugfs_create_file("input_history", 0444, ibm_cffps_dir
,
541 &psu
->debugfs_entries
[CFFPS_DEBUGFS_INPUT_HISTORY
],
543 debugfs_create_file("fru", 0444, ibm_cffps_dir
,
544 &psu
->debugfs_entries
[CFFPS_DEBUGFS_FRU
],
546 debugfs_create_file("part_number", 0444, ibm_cffps_dir
,
547 &psu
->debugfs_entries
[CFFPS_DEBUGFS_PN
],
549 debugfs_create_file("header", 0444, ibm_cffps_dir
,
550 &psu
->debugfs_entries
[CFFPS_DEBUGFS_HEADER
],
552 debugfs_create_file("serial_number", 0444, ibm_cffps_dir
,
553 &psu
->debugfs_entries
[CFFPS_DEBUGFS_SN
],
555 debugfs_create_file("max_power_out", 0444, ibm_cffps_dir
,
556 &psu
->debugfs_entries
[CFFPS_DEBUGFS_MAX_POWER_OUT
],
558 debugfs_create_file("ccin", 0444, ibm_cffps_dir
,
559 &psu
->debugfs_entries
[CFFPS_DEBUGFS_CCIN
],
561 debugfs_create_file("fw_version", 0444, ibm_cffps_dir
,
562 &psu
->debugfs_entries
[CFFPS_DEBUGFS_FW
],
564 debugfs_create_file("on_off_config", 0644, ibm_cffps_dir
,
565 &psu
->debugfs_entries
[CFFPS_DEBUGFS_ON_OFF_CONFIG
],
571 static const struct i2c_device_id ibm_cffps_id
[] = {
572 { "ibm_cffps1", cffps1
},
573 { "ibm_cffps2", cffps2
},
574 { "ibm_cffps", cffps_unknown
},
577 MODULE_DEVICE_TABLE(i2c
, ibm_cffps_id
);
579 static const struct of_device_id ibm_cffps_of_match
[] = {
581 .compatible
= "ibm,cffps1",
582 .data
= (void *)cffps1
585 .compatible
= "ibm,cffps2",
586 .data
= (void *)cffps2
589 .compatible
= "ibm,cffps",
590 .data
= (void *)cffps_unknown
594 MODULE_DEVICE_TABLE(of
, ibm_cffps_of_match
);
596 static struct i2c_driver ibm_cffps_driver
= {
599 .of_match_table
= ibm_cffps_of_match
,
601 .probe
= ibm_cffps_probe
,
602 .remove
= pmbus_do_remove
,
603 .id_table
= ibm_cffps_id
,
606 module_i2c_driver(ibm_cffps_driver
);
608 MODULE_AUTHOR("Eddie James");
609 MODULE_DESCRIPTION("PMBus driver for IBM Common Form Factor power supplies");
610 MODULE_LICENSE("GPL");