1 // SPDX-License-Identifier: GPL-2.0
3 * debugfs attributes for Wilco EC
5 * Copyright 2019 Google LLC
7 * See Documentation/ABI/testing/debugfs-wilco-ec for usage.
10 #include <linux/ctype.h>
11 #include <linux/debugfs.h>
13 #include <linux/module.h>
14 #include <linux/platform_data/wilco-ec.h>
15 #include <linux/platform_device.h>
17 #define DRV_NAME "wilco-ec-debugfs"
19 /* The raw bytes will take up more space when represented as a hex string */
20 #define FORMATTED_BUFFER_SIZE (EC_MAILBOX_DATA_SIZE * 4)
22 struct wilco_ec_debugfs
{
23 struct wilco_ec_device
*ec
;
26 u8 raw_data
[EC_MAILBOX_DATA_SIZE
];
27 u8 formatted_data
[FORMATTED_BUFFER_SIZE
];
29 static struct wilco_ec_debugfs
*debug_info
;
32 * parse_hex_sentence() - Convert a ascii hex representation into byte array.
33 * @in: Input buffer of ascii.
34 * @isize: Length of input buffer.
35 * @out: Output buffer.
36 * @osize: Length of output buffer, e.g. max number of bytes to parse.
38 * An valid input is a series of ascii hexadecimal numbers, separated by spaces.
39 * An example valid input is
40 * " 00 f2 0 000076 6 0 ff"
42 * If an individual "word" within the hex sentence is longer than MAX_WORD_SIZE,
43 * then the sentence is illegal, and parsing will fail.
45 * Return: Number of bytes parsed, or negative error code on failure.
47 static int parse_hex_sentence(const char *in
, int isize
, u8
*out
, int osize
)
53 /* Temp buffer for holding a "word" of chars that represents one byte */
54 #define MAX_WORD_SIZE 16
55 char tmp
[MAX_WORD_SIZE
+ 1];
58 while (word_start
< isize
&& n_parsed
< osize
) {
59 /* Find the start of the next word */
60 while (word_start
< isize
&& isspace(in
[word_start
]))
62 /* reached the end of the input before next word? */
63 if (word_start
>= isize
)
66 /* Find the end of this word */
67 word_end
= word_start
;
68 while (word_end
< isize
&& !isspace(in
[word_end
]))
71 /* Copy to a tmp NULL terminated string */
72 word_len
= word_end
- word_start
;
73 if (word_len
> MAX_WORD_SIZE
)
75 memcpy(tmp
, in
+ word_start
, word_len
);
79 * Convert from hex string, place in output. If fails to parse,
80 * just return -EINVAL because specific error code is only
81 * relevant for this one word, returning it would be confusing.
83 if (kstrtou8(tmp
, 16, &byte
))
85 out
[n_parsed
++] = byte
;
87 word_start
= word_end
;
92 /* The message type takes up two bytes*/
93 #define TYPE_AND_DATA_SIZE ((EC_MAILBOX_DATA_SIZE) + 2)
95 static ssize_t
raw_write(struct file
*file
, const char __user
*user_buf
,
96 size_t count
, loff_t
*ppos
)
98 char *buf
= debug_info
->formatted_data
;
99 struct wilco_ec_message msg
;
100 u8 request_data
[TYPE_AND_DATA_SIZE
];
104 if (count
> FORMATTED_BUFFER_SIZE
)
107 kcount
= simple_write_to_buffer(buf
, FORMATTED_BUFFER_SIZE
, ppos
,
112 ret
= parse_hex_sentence(buf
, kcount
, request_data
, TYPE_AND_DATA_SIZE
);
115 /* Need at least two bytes for message type and one byte of data */
119 msg
.type
= request_data
[0] << 8 | request_data
[1];
121 msg
.request_data
= request_data
+ 2;
122 msg
.request_size
= ret
- 2;
123 memset(debug_info
->raw_data
, 0, sizeof(debug_info
->raw_data
));
124 msg
.response_data
= debug_info
->raw_data
;
125 msg
.response_size
= EC_MAILBOX_DATA_SIZE
;
127 ret
= wilco_ec_mailbox(debug_info
->ec
, &msg
);
130 debug_info
->response_size
= ret
;
135 static ssize_t
raw_read(struct file
*file
, char __user
*user_buf
, size_t count
,
140 if (debug_info
->response_size
) {
141 fmt_len
= hex_dump_to_buffer(debug_info
->raw_data
,
142 debug_info
->response_size
,
143 16, 1, debug_info
->formatted_data
,
144 sizeof(debug_info
->formatted_data
),
146 /* Only return response the first time it is read */
147 debug_info
->response_size
= 0;
150 return simple_read_from_buffer(user_buf
, count
, ppos
,
151 debug_info
->formatted_data
, fmt_len
);
154 static const struct file_operations fops_raw
= {
155 .owner
= THIS_MODULE
,
161 #define CMD_KB_CHROME 0x88
162 #define SUB_CMD_H1_GPIO 0x0A
163 #define SUB_CMD_TEST_EVENT 0x0B
166 u8 cmd
; /* Always CMD_KB_CHROME */
172 u8 status
; /* 0 if allowed */
176 static int send_ec_cmd(struct wilco_ec_device
*ec
, u8 sub_cmd
, u8
*out_val
)
178 struct ec_request rq
;
179 struct ec_response rs
;
180 struct wilco_ec_message msg
;
183 memset(&rq
, 0, sizeof(rq
));
184 rq
.cmd
= CMD_KB_CHROME
;
185 rq
.sub_cmd
= sub_cmd
;
187 memset(&msg
, 0, sizeof(msg
));
188 msg
.type
= WILCO_EC_MSG_LEGACY
;
189 msg
.request_data
= &rq
;
190 msg
.request_size
= sizeof(rq
);
191 msg
.response_data
= &rs
;
192 msg
.response_size
= sizeof(rs
);
193 ret
= wilco_ec_mailbox(ec
, &msg
);
205 * h1_gpio_get() - Gets h1 gpio status.
206 * @arg: The wilco EC device.
207 * @val: BIT(0)=ENTRY_TO_FACT_MODE, BIT(1)=SPI_CHROME_SEL
209 static int h1_gpio_get(void *arg
, u64
*val
)
213 ret
= send_ec_cmd(arg
, SUB_CMD_H1_GPIO
, (u8
*)val
);
219 DEFINE_DEBUGFS_ATTRIBUTE(fops_h1_gpio
, h1_gpio_get
, NULL
, "0x%02llx\n");
222 * test_event_set() - Sends command to EC to cause an EC test event.
223 * @arg: The wilco EC device.
226 static int test_event_set(void *arg
, u64 val
)
230 return send_ec_cmd(arg
, SUB_CMD_TEST_EVENT
, &ret
);
233 /* Format is unused since it is only required for get method which is NULL */
234 DEFINE_DEBUGFS_ATTRIBUTE(fops_test_event
, NULL
, test_event_set
, "%llu\n");
237 * wilco_ec_debugfs_probe() - Create the debugfs node
238 * @pdev: The platform device, probably created in core.c
240 * Try to create a debugfs node. If it fails, then we don't want to change
241 * behavior at all, this is for debugging after all. Just fail silently.
245 static int wilco_ec_debugfs_probe(struct platform_device
*pdev
)
247 struct wilco_ec_device
*ec
= dev_get_drvdata(pdev
->dev
.parent
);
249 debug_info
= devm_kzalloc(&pdev
->dev
, sizeof(*debug_info
), GFP_KERNEL
);
253 debug_info
->dir
= debugfs_create_dir("wilco_ec", NULL
);
254 if (!debug_info
->dir
)
256 debugfs_create_file("raw", 0644, debug_info
->dir
, NULL
, &fops_raw
);
257 debugfs_create_file("h1_gpio", 0444, debug_info
->dir
, ec
,
259 debugfs_create_file("test_event", 0200, debug_info
->dir
, ec
,
265 static int wilco_ec_debugfs_remove(struct platform_device
*pdev
)
267 debugfs_remove_recursive(debug_info
->dir
);
272 static struct platform_driver wilco_ec_debugfs_driver
= {
276 .probe
= wilco_ec_debugfs_probe
,
277 .remove
= wilco_ec_debugfs_remove
,
280 module_platform_driver(wilco_ec_debugfs_driver
);
282 MODULE_ALIAS("platform:" DRV_NAME
);
283 MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
284 MODULE_LICENSE("GPL v2");
285 MODULE_DESCRIPTION("Wilco EC debugfs driver");