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"
49 static int append_str(char *buf
, int pos
, const char *fmt
, ...)
55 i
= vsnprintf(buf
+ pos
, BUF_SIZE
- pos
, fmt
, args
);
61 static struct ec_response_pd_log
*ec_get_log_entry(struct logger_data
*logger
)
63 struct cros_ec_dev
*ec_dev
= logger
->ec_dev
;
64 struct cros_ec_command
*msg
;
67 msg
= (struct cros_ec_command
*)logger
->ec_buffer
;
69 msg
->command
= ec_dev
->cmd_offset
+ EC_CMD_PD_GET_LOG_ENTRY
;
70 msg
->insize
= CROS_USBPD_LOG_RESP_SIZE
;
72 ret
= cros_ec_cmd_xfer_status(ec_dev
->ec_dev
, msg
);
76 return (struct ec_response_pd_log
*)msg
->data
;
79 static void cros_usbpd_print_log_entry(struct ec_response_pd_log
*r
,
82 const char *fault
, *role
, *chg_type
;
83 struct usb_chg_measures
*meas
;
84 struct mcdp_info
*minfo
;
85 int role_idx
, type_idx
;
86 char buf
[BUF_SIZE
+ 1];
92 /* The timestamp is the number of 1024th of seconds in the past */
93 tstamp
= ktime_sub_us(tstamp
, r
->timestamp
<< PD_LOG_TIMESTAMP_SHIFT
);
94 rt
= rtc_ktime_to_tm(tstamp
);
97 case PD_EVENT_MCU_CHARGE
:
98 if (r
->data
& CHARGE_FLAGS_OVERRIDE
)
99 len
+= append_str(buf
, len
, "override ");
101 if (r
->data
& CHARGE_FLAGS_DELAYED_OVERRIDE
)
102 len
+= append_str(buf
, len
, "pending_override ");
104 role_idx
= r
->data
& CHARGE_FLAGS_ROLE_MASK
;
105 role
= role_idx
< ARRAY_SIZE(role_names
) ?
106 role_names
[role_idx
] : "Unknown";
108 type_idx
= (r
->data
& CHARGE_FLAGS_TYPE_MASK
)
109 >> CHARGE_FLAGS_TYPE_SHIFT
;
111 chg_type
= type_idx
< ARRAY_SIZE(chg_type_names
) ?
112 chg_type_names
[type_idx
] : "???";
114 if (role_idx
== USB_PD_PORT_POWER_DISCONNECTED
||
115 role_idx
== USB_PD_PORT_POWER_SOURCE
) {
116 len
+= append_str(buf
, len
, "%s", role
);
120 meas
= (struct usb_chg_measures
*)r
->payload
;
121 len
+= append_str(buf
, len
, "%s %s %s %dmV max %dmV / %dmA",
122 role
, r
->data
& CHARGE_FLAGS_DUAL_ROLE
?
124 chg_type
, meas
->voltage_now
,
125 meas
->voltage_max
, meas
->current_max
);
127 case PD_EVENT_ACC_RW_FAIL
:
128 len
+= append_str(buf
, len
, "RW signature check failed");
130 case PD_EVENT_PS_FAULT
:
131 fault
= r
->data
< ARRAY_SIZE(fault_names
) ? fault_names
[r
->data
]
133 len
+= append_str(buf
, len
, "Power supply fault: %s", fault
);
135 case PD_EVENT_VIDEO_DP_MODE
:
136 len
+= append_str(buf
, len
, "DP mode %sabled", r
->data
== 1 ?
139 case PD_EVENT_VIDEO_CODEC
:
140 minfo
= (struct mcdp_info
*)r
->payload
;
141 len
+= append_str(buf
, len
, "HDMI info: family:%04x chipid:%04x ",
142 MCDP_FAMILY(minfo
->family
),
143 MCDP_CHIPID(minfo
->chipid
));
144 len
+= append_str(buf
, len
, "irom:%d.%d.%d fw:%d.%d.%d",
145 minfo
->irom
.major
, minfo
->irom
.minor
,
146 minfo
->irom
.build
, minfo
->fw
.major
,
147 minfo
->fw
.minor
, minfo
->fw
.build
);
150 len
+= append_str(buf
, len
, "Event %02x (%04x) [", r
->type
,
153 for (i
= 0; i
< PD_LOG_SIZE(r
->size_port
); i
++)
154 len
+= append_str(buf
, len
, "%02x ", r
->payload
[i
]);
156 len
+= append_str(buf
, len
, "]");
160 div_s64_rem(ktime_to_ms(tstamp
), MSEC_PER_SEC
, &rem
);
161 pr_info("PDLOG %d/%02d/%02d %02d:%02d:%02d.%03d P%d %s\n",
162 rt
.tm_year
+ 1900, rt
.tm_mon
+ 1, rt
.tm_mday
,
163 rt
.tm_hour
, rt
.tm_min
, rt
.tm_sec
, rem
,
164 PD_LOG_PORT(r
->size_port
), buf
);
167 static void cros_usbpd_log_check(struct work_struct
*work
)
169 struct logger_data
*logger
= container_of(to_delayed_work(work
),
172 struct device
*dev
= logger
->dev
;
173 struct ec_response_pd_log
*r
;
177 while (entries
++ < CROS_USBPD_MAX_LOG_ENTRIES
) {
178 r
= ec_get_log_entry(logger
);
179 now
= ktime_get_real();
181 dev_dbg(dev
, "Cannot get PD log %ld\n", PTR_ERR(r
));
184 if (r
->type
== PD_EVENT_NO_ENTRY
)
187 cros_usbpd_print_log_entry(r
, now
);
190 queue_delayed_work(logger
->log_workqueue
, &logger
->log_work
,
191 CROS_USBPD_LOG_UPDATE_DELAY
);
194 static int cros_usbpd_logger_probe(struct platform_device
*pd
)
196 struct cros_ec_dev
*ec_dev
= dev_get_drvdata(pd
->dev
.parent
);
197 struct device
*dev
= &pd
->dev
;
198 struct logger_data
*logger
;
200 logger
= devm_kzalloc(dev
, sizeof(*logger
), GFP_KERNEL
);
205 logger
->ec_dev
= ec_dev
;
207 platform_set_drvdata(pd
, logger
);
209 /* Retrieve PD event logs periodically */
210 INIT_DELAYED_WORK(&logger
->log_work
, cros_usbpd_log_check
);
211 logger
->log_workqueue
= create_singlethread_workqueue("cros_usbpd_log");
212 if (!logger
->log_workqueue
)
215 queue_delayed_work(logger
->log_workqueue
, &logger
->log_work
,
216 CROS_USBPD_LOG_UPDATE_DELAY
);
221 static int cros_usbpd_logger_remove(struct platform_device
*pd
)
223 struct logger_data
*logger
= platform_get_drvdata(pd
);
225 cancel_delayed_work_sync(&logger
->log_work
);
226 destroy_workqueue(logger
->log_workqueue
);
231 static int __maybe_unused
cros_usbpd_logger_resume(struct device
*dev
)
233 struct logger_data
*logger
= dev_get_drvdata(dev
);
235 queue_delayed_work(logger
->log_workqueue
, &logger
->log_work
,
236 CROS_USBPD_LOG_UPDATE_DELAY
);
241 static int __maybe_unused
cros_usbpd_logger_suspend(struct device
*dev
)
243 struct logger_data
*logger
= dev_get_drvdata(dev
);
245 cancel_delayed_work_sync(&logger
->log_work
);
250 static SIMPLE_DEV_PM_OPS(cros_usbpd_logger_pm_ops
, cros_usbpd_logger_suspend
,
251 cros_usbpd_logger_resume
);
253 static struct platform_driver cros_usbpd_logger_driver
= {
256 .pm
= &cros_usbpd_logger_pm_ops
,
258 .probe
= cros_usbpd_logger_probe
,
259 .remove
= cros_usbpd_logger_remove
,
262 module_platform_driver(cros_usbpd_logger_driver
);
264 MODULE_LICENSE("GPL v2");
265 MODULE_DESCRIPTION("Logging driver for ChromeOS EC USBPD Charger.");
266 MODULE_ALIAS("platform:" DRV_NAME
);