1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2024 Google LLC
5 * This driver provides the ability to control GPIOs on the Chrome OS EC.
6 * There isn't any direction control, and setting values on GPIOs is only
7 * possible when the system is unlocked.
10 #include <linux/bitops.h>
11 #include <linux/device.h>
12 #include <linux/errno.h>
13 #include <linux/gpio/driver.h>
14 #include <linux/kernel.h>
15 #include <linux/mod_devicetable.h>
16 #include <linux/module.h>
17 #include <linux/platform_data/cros_ec_commands.h>
18 #include <linux/platform_data/cros_ec_proto.h>
19 #include <linux/platform_device.h>
20 #include <linux/property.h>
21 #include <linux/slab.h>
23 /* Prefix all names to avoid collisions with EC <-> AP nets */
24 static const char cros_ec_gpio_prefix
[] = "EC:";
26 /* Setting gpios is only supported when the system is unlocked */
27 static void cros_ec_gpio_set(struct gpio_chip
*gc
, unsigned int gpio
, int val
)
29 const char *name
= gc
->names
[gpio
] + strlen(cros_ec_gpio_prefix
);
30 struct cros_ec_device
*cros_ec
= gpiochip_get_data(gc
);
31 struct ec_params_gpio_set params
= {
37 copied
= strscpy(params
.name
, name
, sizeof(params
.name
));
41 ret
= cros_ec_cmd(cros_ec
, 0, EC_CMD_GPIO_SET
, ¶ms
,
42 sizeof(params
), NULL
, 0);
44 dev_err(gc
->parent
, "error setting gpio%d (%s) on EC: %d\n", gpio
, name
, ret
);
47 static int cros_ec_gpio_get(struct gpio_chip
*gc
, unsigned int gpio
)
49 const char *name
= gc
->names
[gpio
] + strlen(cros_ec_gpio_prefix
);
50 struct cros_ec_device
*cros_ec
= gpiochip_get_data(gc
);
51 struct ec_params_gpio_get params
;
52 struct ec_response_gpio_get response
;
56 copied
= strscpy(params
.name
, name
, sizeof(params
.name
));
60 ret
= cros_ec_cmd(cros_ec
, 0, EC_CMD_GPIO_GET
, ¶ms
,
61 sizeof(params
), &response
, sizeof(response
));
63 dev_err(gc
->parent
, "error getting gpio%d (%s) on EC: %d\n", gpio
, name
, ret
);
70 #define CROS_EC_GPIO_INPUT BIT(8)
71 #define CROS_EC_GPIO_OUTPUT BIT(9)
73 static int cros_ec_gpio_get_direction(struct gpio_chip
*gc
, unsigned int gpio
)
75 const char *name
= gc
->names
[gpio
] + strlen(cros_ec_gpio_prefix
);
76 struct cros_ec_device
*cros_ec
= gpiochip_get_data(gc
);
77 struct ec_params_gpio_get_v1 params
= {
78 .subcmd
= EC_GPIO_GET_INFO
,
79 .get_info
.index
= gpio
,
81 struct ec_response_gpio_get_v1 response
;
84 ret
= cros_ec_cmd(cros_ec
, 1, EC_CMD_GPIO_GET
, ¶ms
,
85 sizeof(params
), &response
, sizeof(response
));
87 dev_err(gc
->parent
, "error getting direction of gpio%d (%s) on EC: %d\n", gpio
, name
, ret
);
91 if (response
.get_info
.flags
& CROS_EC_GPIO_INPUT
)
92 return GPIO_LINE_DIRECTION_IN
;
94 if (response
.get_info
.flags
& CROS_EC_GPIO_OUTPUT
)
95 return GPIO_LINE_DIRECTION_OUT
;
100 /* Query EC for all gpio line names */
101 static int cros_ec_gpio_init_names(struct cros_ec_device
*cros_ec
, struct gpio_chip
*gc
)
103 struct ec_params_gpio_get_v1 params
= {
104 .subcmd
= EC_GPIO_GET_INFO
,
106 struct ec_response_gpio_get_v1 response
;
108 /* EC may not NUL terminate */
109 size_t name_len
= strlen(cros_ec_gpio_prefix
) + sizeof(response
.get_info
.name
) + 1;
114 names
= devm_kcalloc(gc
->parent
, gc
->ngpio
, sizeof(*names
), GFP_KERNEL
);
119 str
= devm_kcalloc(gc
->parent
, gc
->ngpio
, name_len
, GFP_KERNEL
);
123 /* Get gpio line names one at a time */
124 for (i
= 0; i
< gc
->ngpio
; i
++) {
125 params
.get_info
.index
= i
;
126 ret
= cros_ec_cmd(cros_ec
, 1, EC_CMD_GPIO_GET
, ¶ms
,
127 sizeof(params
), &response
, sizeof(response
));
129 dev_err_probe(gc
->parent
, ret
, "error getting gpio%d info\n", i
);
134 copied
= scnprintf(str
, name_len
, "%s%s", cros_ec_gpio_prefix
,
135 response
.get_info
.name
);
145 /* Query EC for number of gpios */
146 static int cros_ec_gpio_ngpios(struct cros_ec_device
*cros_ec
)
148 struct ec_params_gpio_get_v1 params
= {
149 .subcmd
= EC_GPIO_GET_COUNT
,
151 struct ec_response_gpio_get_v1 response
;
154 ret
= cros_ec_cmd(cros_ec
, 1, EC_CMD_GPIO_GET
, ¶ms
,
155 sizeof(params
), &response
, sizeof(response
));
159 return response
.get_count
.val
;
162 static int cros_ec_gpio_probe(struct platform_device
*pdev
)
164 struct device
*dev
= &pdev
->dev
;
165 struct device
*parent
= dev
->parent
;
166 struct cros_ec_dev
*ec_dev
= dev_get_drvdata(parent
);
167 struct cros_ec_device
*cros_ec
= ec_dev
->ec_dev
;
168 struct gpio_chip
*gc
;
172 /* Use the fwnode from the protocol device, e.g. cros-ec-spi */
173 device_set_node(dev
, dev_fwnode(cros_ec
->dev
));
175 ngpios
= cros_ec_gpio_ngpios(cros_ec
);
177 dev_err_probe(dev
, ngpios
, "error getting gpio count\n");
181 gc
= devm_kzalloc(dev
, sizeof(*gc
), GFP_KERNEL
);
187 ret
= cros_ec_gpio_init_names(cros_ec
, gc
);
191 gc
->can_sleep
= true;
192 gc
->label
= dev_name(dev
);
194 gc
->set
= cros_ec_gpio_set
;
195 gc
->get
= cros_ec_gpio_get
;
196 gc
->get_direction
= cros_ec_gpio_get_direction
;
198 return devm_gpiochip_add_data(dev
, gc
, cros_ec
);
201 static const struct platform_device_id cros_ec_gpio_id
[] = {
202 { "cros-ec-gpio", 0 },
205 MODULE_DEVICE_TABLE(platform
, cros_ec_gpio_id
);
207 static struct platform_driver cros_ec_gpio_driver
= {
208 .probe
= cros_ec_gpio_probe
,
210 .name
= "cros-ec-gpio",
212 .id_table
= cros_ec_gpio_id
,
214 module_platform_driver(cros_ec_gpio_driver
);
216 MODULE_DESCRIPTION("ChromeOS EC GPIO Driver");
217 MODULE_LICENSE("GPL");