1 // SPDX-License-Identifier: GPL-2.0
3 * Logging driver for ChromeOS EC based USBPD Charger.
5 * Copyright 2018 Google LLC.
8 #include <linux/ktime.h>
9 #include <linux/math64.h>
10 #include <linux/module.h>
11 #include <linux/platform_data/cros_ec_commands.h>
12 #include <linux/platform_data/cros_ec_proto.h>
13 #include <linux/platform_device.h>
14 #include <linux/rtc.h>
16 #define DRV_NAME "cros-usbpd-logger"
18 #define CROS_USBPD_MAX_LOG_ENTRIES 30
19 #define CROS_USBPD_LOG_UPDATE_DELAY msecs_to_jiffies(60000)
20 #define CROS_USBPD_DATA_SIZE 16
21 #define CROS_USBPD_LOG_RESP_SIZE (sizeof(struct ec_response_pd_log) + \
23 #define CROS_USBPD_BUFFER_SIZE (sizeof(struct cros_ec_command) + \
24 CROS_USBPD_LOG_RESP_SIZE)
25 /* Buffer for building the PDLOG string */
30 struct cros_ec_dev
*ec_dev
;
31 u8 ec_buffer
[CROS_USBPD_BUFFER_SIZE
];
32 struct delayed_work log_work
;
33 struct workqueue_struct
*log_workqueue
;
36 static const char * const chg_type_names
[] = {
37 "None", "PD", "Type-C", "Proprietary", "DCP", "CDP", "SDP",
41 static const char * const role_names
[] = {
42 "Disconnected", "SRC", "SNK", "SNK (not charging)"
45 static const char * const fault_names
[] = {
46 "---", "OCP", "fast OCP", "OVP", "Discharge"
50 static int append_str(char *buf
, int pos
, const char *fmt
, ...)
56 i
= vsnprintf(buf
+ pos
, BUF_SIZE
- pos
, fmt
, args
);
62 static struct ec_response_pd_log
*ec_get_log_entry(struct logger_data
*logger
)
64 struct cros_ec_dev
*ec_dev
= logger
->ec_dev
;
65 struct cros_ec_command
*msg
;
68 msg
= (struct cros_ec_command
*)logger
->ec_buffer
;
70 msg
->command
= ec_dev
->cmd_offset
+ EC_CMD_PD_GET_LOG_ENTRY
;
71 msg
->insize
= CROS_USBPD_LOG_RESP_SIZE
;
73 ret
= cros_ec_cmd_xfer_status(ec_dev
->ec_dev
, msg
);
77 return (struct ec_response_pd_log
*)msg
->data
;
80 static void cros_usbpd_print_log_entry(struct ec_response_pd_log
*r
,
83 const char *fault
, *role
, *chg_type
;
84 struct usb_chg_measures
*meas
;
85 struct mcdp_info
*minfo
;
86 int role_idx
, type_idx
;
87 char buf
[BUF_SIZE
+ 1];
93 /* The timestamp is the number of 1024th of seconds in the past */
94 tstamp
= ktime_sub_us(tstamp
, r
->timestamp
<< PD_LOG_TIMESTAMP_SHIFT
);
95 rt
= rtc_ktime_to_tm(tstamp
);
98 case PD_EVENT_MCU_CHARGE
:
99 if (r
->data
& CHARGE_FLAGS_OVERRIDE
)
100 len
+= append_str(buf
, len
, "override ");
102 if (r
->data
& CHARGE_FLAGS_DELAYED_OVERRIDE
)
103 len
+= append_str(buf
, len
, "pending_override ");
105 role_idx
= r
->data
& CHARGE_FLAGS_ROLE_MASK
;
106 role
= role_idx
< ARRAY_SIZE(role_names
) ?
107 role_names
[role_idx
] : "Unknown";
109 type_idx
= (r
->data
& CHARGE_FLAGS_TYPE_MASK
)
110 >> CHARGE_FLAGS_TYPE_SHIFT
;
112 chg_type
= type_idx
< ARRAY_SIZE(chg_type_names
) ?
113 chg_type_names
[type_idx
] : "???";
115 if (role_idx
== USB_PD_PORT_POWER_DISCONNECTED
||
116 role_idx
== USB_PD_PORT_POWER_SOURCE
) {
117 len
+= append_str(buf
, len
, "%s", role
);
121 meas
= (struct usb_chg_measures
*)r
->payload
;
122 len
+= append_str(buf
, len
, "%s %s %s %dmV max %dmV / %dmA",
123 role
, r
->data
& CHARGE_FLAGS_DUAL_ROLE
?
125 chg_type
, meas
->voltage_now
,
126 meas
->voltage_max
, meas
->current_max
);
128 case PD_EVENT_ACC_RW_FAIL
:
129 len
+= append_str(buf
, len
, "RW signature check failed");
131 case PD_EVENT_PS_FAULT
:
132 fault
= r
->data
< ARRAY_SIZE(fault_names
) ? fault_names
[r
->data
]
134 len
+= append_str(buf
, len
, "Power supply fault: %s", fault
);
136 case PD_EVENT_VIDEO_DP_MODE
:
137 len
+= append_str(buf
, len
, "DP mode %sabled", r
->data
== 1 ?
140 case PD_EVENT_VIDEO_CODEC
:
141 minfo
= (struct mcdp_info
*)r
->payload
;
142 len
+= append_str(buf
, len
, "HDMI info: family:%04x chipid:%04x ",
143 MCDP_FAMILY(minfo
->family
),
144 MCDP_CHIPID(minfo
->chipid
));
145 len
+= append_str(buf
, len
, "irom:%d.%d.%d fw:%d.%d.%d",
146 minfo
->irom
.major
, minfo
->irom
.minor
,
147 minfo
->irom
.build
, minfo
->fw
.major
,
148 minfo
->fw
.minor
, minfo
->fw
.build
);
151 len
+= append_str(buf
, len
, "Event %02x (%04x) [", r
->type
,
154 for (i
= 0; i
< PD_LOG_SIZE(r
->size_port
); i
++)
155 len
+= append_str(buf
, len
, "%02x ", r
->payload
[i
]);
157 len
+= append_str(buf
, len
, "]");
161 div_s64_rem(ktime_to_ms(tstamp
), MSEC_PER_SEC
, &rem
);
162 pr_info("PDLOG %d/%02d/%02d %02d:%02d:%02d.%03d P%d %s\n",
163 rt
.tm_year
+ 1900, rt
.tm_mon
+ 1, rt
.tm_mday
,
164 rt
.tm_hour
, rt
.tm_min
, rt
.tm_sec
, rem
,
165 PD_LOG_PORT(r
->size_port
), buf
);
168 static void cros_usbpd_log_check(struct work_struct
*work
)
170 struct logger_data
*logger
= container_of(to_delayed_work(work
),
173 struct device
*dev
= logger
->dev
;
174 struct ec_response_pd_log
*r
;
178 while (entries
++ < CROS_USBPD_MAX_LOG_ENTRIES
) {
179 r
= ec_get_log_entry(logger
);
180 now
= ktime_get_real();
182 dev_dbg(dev
, "Cannot get PD log %ld\n", PTR_ERR(r
));
185 if (r
->type
== PD_EVENT_NO_ENTRY
)
188 cros_usbpd_print_log_entry(r
, now
);
191 queue_delayed_work(logger
->log_workqueue
, &logger
->log_work
,
192 CROS_USBPD_LOG_UPDATE_DELAY
);
195 static int cros_usbpd_logger_probe(struct platform_device
*pd
)
197 struct cros_ec_dev
*ec_dev
= dev_get_drvdata(pd
->dev
.parent
);
198 struct device
*dev
= &pd
->dev
;
199 struct logger_data
*logger
;
201 logger
= devm_kzalloc(dev
, sizeof(*logger
), GFP_KERNEL
);
206 logger
->ec_dev
= ec_dev
;
208 platform_set_drvdata(pd
, logger
);
210 /* Retrieve PD event logs periodically */
211 INIT_DELAYED_WORK(&logger
->log_work
, cros_usbpd_log_check
);
212 logger
->log_workqueue
= create_singlethread_workqueue("cros_usbpd_log");
213 if (!logger
->log_workqueue
)
216 queue_delayed_work(logger
->log_workqueue
, &logger
->log_work
,
217 CROS_USBPD_LOG_UPDATE_DELAY
);
222 static int cros_usbpd_logger_remove(struct platform_device
*pd
)
224 struct logger_data
*logger
= platform_get_drvdata(pd
);
226 cancel_delayed_work_sync(&logger
->log_work
);
227 destroy_workqueue(logger
->log_workqueue
);
232 static int __maybe_unused
cros_usbpd_logger_resume(struct device
*dev
)
234 struct logger_data
*logger
= dev_get_drvdata(dev
);
236 queue_delayed_work(logger
->log_workqueue
, &logger
->log_work
,
237 CROS_USBPD_LOG_UPDATE_DELAY
);
242 static int __maybe_unused
cros_usbpd_logger_suspend(struct device
*dev
)
244 struct logger_data
*logger
= dev_get_drvdata(dev
);
246 cancel_delayed_work_sync(&logger
->log_work
);
251 static SIMPLE_DEV_PM_OPS(cros_usbpd_logger_pm_ops
, cros_usbpd_logger_suspend
,
252 cros_usbpd_logger_resume
);
254 static struct platform_driver cros_usbpd_logger_driver
= {
257 .pm
= &cros_usbpd_logger_pm_ops
,
259 .probe
= cros_usbpd_logger_probe
,
260 .remove
= cros_usbpd_logger_remove
,
263 module_platform_driver(cros_usbpd_logger_driver
);
265 MODULE_LICENSE("GPL v2");
266 MODULE_DESCRIPTION("Logging driver for ChromeOS EC USBPD Charger.");
267 MODULE_ALIAS("platform:" DRV_NAME
);