xref: /optee_os/core/include/drivers/gpio.h (revision 8fd620f75b68cd47c13807b45b78ea9c931de9b6)
16dcd18c8SClément Léger /* SPDX-License-Identifier: BSD-2-Clause */
26dcd18c8SClément Léger /*
36dcd18c8SClément Léger  * Copyright (c) 2016, Linaro Limited
46dcd18c8SClément Léger  */
56dcd18c8SClément Léger 
66dcd18c8SClément Léger #ifndef DRIVERS_GPIO_H
76dcd18c8SClément Léger #define DRIVERS_GPIO_H
86dcd18c8SClément Léger 
983f24981SEtienne Carriere #include <assert.h>
104fc179b6SThomas Perrot #include <dt-bindings/gpio/gpio.h>
114fc179b6SThomas Perrot #include <kernel/dt_driver.h>
124fc179b6SThomas Perrot #include <stdint.h>
134fc179b6SThomas Perrot #include <tee_api_types.h>
144fc179b6SThomas Perrot 
154fc179b6SThomas Perrot /**
164fc179b6SThomas Perrot  * GPIO_DT_DECLARE - Declare a GPIO controller driver with a single
174fc179b6SThomas Perrot  * device tree compatible string.
184fc179b6SThomas Perrot  *
194fc179b6SThomas Perrot  * @__name: GPIO controller driver name
204fc179b6SThomas Perrot  * @__compat: Compatible string
214fc179b6SThomas Perrot  * @__probe: GPIO controller probe function
224fc179b6SThomas Perrot  */
234fc179b6SThomas Perrot #define GPIO_DT_DECLARE(__name, __compat, __probe) \
244fc179b6SThomas Perrot 	static const struct dt_device_match __name ## _match_table[] = { \
254fc179b6SThomas Perrot 		{ .compatible = __compat }, \
264fc179b6SThomas Perrot 		{ } \
274fc179b6SThomas Perrot 	}; \
284fc179b6SThomas Perrot 	DEFINE_DT_DRIVER(__name ## _dt_driver) = { \
294fc179b6SThomas Perrot 		.name = # __name, \
304fc179b6SThomas Perrot 		.type = DT_DRIVER_GPIO, \
314fc179b6SThomas Perrot 		.match_table = __name ## _match_table, \
324fc179b6SThomas Perrot 		.probe = __probe, \
334fc179b6SThomas Perrot 	}
344fc179b6SThomas Perrot 
356dcd18c8SClément Léger enum gpio_dir {
366dcd18c8SClément Léger 	GPIO_DIR_OUT,
376dcd18c8SClément Léger 	GPIO_DIR_IN
386dcd18c8SClément Léger };
396dcd18c8SClément Léger 
406dcd18c8SClément Léger enum gpio_level {
416dcd18c8SClément Léger 	GPIO_LEVEL_LOW,
426dcd18c8SClément Léger 	GPIO_LEVEL_HIGH
436dcd18c8SClément Léger };
446dcd18c8SClément Léger 
456dcd18c8SClément Léger enum gpio_interrupt {
466dcd18c8SClément Léger 	GPIO_INTERRUPT_DISABLE,
476dcd18c8SClément Léger 	GPIO_INTERRUPT_ENABLE
486dcd18c8SClément Léger };
496dcd18c8SClément Léger 
5083f24981SEtienne Carriere struct gpio;
5183f24981SEtienne Carriere struct gpio_ops;
5283f24981SEtienne Carriere 
536dcd18c8SClément Léger struct gpio_chip {
546dcd18c8SClément Léger 	const struct gpio_ops *ops;
556dcd18c8SClément Léger };
566dcd18c8SClément Léger 
576dcd18c8SClément Léger struct gpio_ops {
5824b364c8SEtienne Carriere 	/* Get GPIO direction current configuration */
596dcd18c8SClément Léger 	enum gpio_dir (*get_direction)(struct gpio_chip *chip,
606dcd18c8SClément Léger 				       unsigned int gpio_pin);
6124b364c8SEtienne Carriere 	/* Set GPIO direction configuration */
626dcd18c8SClément Léger 	void (*set_direction)(struct gpio_chip *chip, unsigned int gpio_pin,
636dcd18c8SClément Léger 			      enum gpio_dir direction);
6424b364c8SEtienne Carriere 	/* Get GPIO current level */
656dcd18c8SClément Léger 	enum gpio_level (*get_value)(struct gpio_chip *chip,
666dcd18c8SClément Léger 				     unsigned int gpio_pin);
6724b364c8SEtienne Carriere 	/* Set GPIO level */
686dcd18c8SClément Léger 	void (*set_value)(struct gpio_chip *chip, unsigned int gpio_pin,
696dcd18c8SClément Léger 			  enum gpio_level value);
7024b364c8SEtienne Carriere 	/* Get GPIO interrupt state */
716dcd18c8SClément Léger 	enum gpio_interrupt (*get_interrupt)(struct gpio_chip *chip,
726dcd18c8SClément Léger 					     unsigned int gpio_pin);
7324b364c8SEtienne Carriere 	/* Enable or disable a GPIO interrupt */
746dcd18c8SClément Léger 	void (*set_interrupt)(struct gpio_chip *chip, unsigned int gpio_pin,
756dcd18c8SClément Léger 			      enum gpio_interrupt enable_disable);
7683f24981SEtienne Carriere 	/* Release GPIO resources */
7783f24981SEtienne Carriere 	void (*put)(struct gpio_chip *chip, struct gpio *gpio);
786dcd18c8SClément Léger };
796dcd18c8SClément Léger 
804fc179b6SThomas Perrot /*
814fc179b6SThomas Perrot  * struct gpio - GPIO pin description
824fc179b6SThomas Perrot  * @chip: GPIO controller chip reference
834fc179b6SThomas Perrot  * @dt_flags: Pin boolean properties set from DT node
844fc179b6SThomas Perrot  * @pin: Pin number in GPIO controller
854fc179b6SThomas Perrot  */
864fc179b6SThomas Perrot struct gpio {
874fc179b6SThomas Perrot 	struct gpio_chip *chip;
884fc179b6SThomas Perrot 	uint32_t dt_flags;
894fc179b6SThomas Perrot 	unsigned int pin;
904fc179b6SThomas Perrot };
914fc179b6SThomas Perrot 
924fc179b6SThomas Perrot static inline bool gpio_ops_is_valid(const struct gpio_ops *ops)
934fc179b6SThomas Perrot {
944fc179b6SThomas Perrot 	return ops->set_direction && ops->get_direction && ops->get_value &&
954fc179b6SThomas Perrot 	       ops->set_value;
964fc179b6SThomas Perrot }
974fc179b6SThomas Perrot 
984fc179b6SThomas Perrot static inline void gpio_set_direction(struct gpio *gpio, enum gpio_dir dir)
994fc179b6SThomas Perrot {
1004fc179b6SThomas Perrot 	gpio->chip->ops->set_direction(gpio->chip, gpio->pin, dir);
1014fc179b6SThomas Perrot }
1024fc179b6SThomas Perrot 
1034fc179b6SThomas Perrot static inline enum gpio_dir gpio_get_direction(struct gpio *gpio)
1044fc179b6SThomas Perrot {
1054fc179b6SThomas Perrot 	return gpio->chip->ops->get_direction(gpio->chip, gpio->pin);
1064fc179b6SThomas Perrot }
1074fc179b6SThomas Perrot 
1084fc179b6SThomas Perrot static inline void gpio_set_value(struct gpio *gpio, enum gpio_level value)
1094fc179b6SThomas Perrot {
1104fc179b6SThomas Perrot 	if (gpio->dt_flags & GPIO_ACTIVE_LOW)
1114fc179b6SThomas Perrot 		value = !value;
1124fc179b6SThomas Perrot 
1134fc179b6SThomas Perrot 	gpio->chip->ops->set_value(gpio->chip, gpio->pin, value);
1144fc179b6SThomas Perrot }
1154fc179b6SThomas Perrot 
1164fc179b6SThomas Perrot static inline enum gpio_level gpio_get_value(struct gpio *gpio)
1174fc179b6SThomas Perrot {
1184fc179b6SThomas Perrot 	enum gpio_level value = GPIO_LEVEL_LOW;
1194fc179b6SThomas Perrot 
1204fc179b6SThomas Perrot 	value = gpio->chip->ops->get_value(gpio->chip, gpio->pin);
1214fc179b6SThomas Perrot 
1224fc179b6SThomas Perrot 	if (gpio->dt_flags & GPIO_ACTIVE_LOW)
1234fc179b6SThomas Perrot 		value = !value;
1244fc179b6SThomas Perrot 
1254fc179b6SThomas Perrot 	return value;
1264fc179b6SThomas Perrot }
1274fc179b6SThomas Perrot 
12883f24981SEtienne Carriere static inline void gpio_put(struct gpio *gpio)
12983f24981SEtienne Carriere {
13083f24981SEtienne Carriere 	assert(!gpio || (gpio->chip && gpio->chip->ops));
13183f24981SEtienne Carriere 
13283f24981SEtienne Carriere 	if (gpio && gpio->chip->ops->put)
13383f24981SEtienne Carriere 		gpio->chip->ops->put(gpio->chip, gpio);
13483f24981SEtienne Carriere }
13583f24981SEtienne Carriere 
1364fc179b6SThomas Perrot #if defined(CFG_DT) && defined(CFG_DRIVERS_GPIO)
1374fc179b6SThomas Perrot /**
1384fc179b6SThomas Perrot  * gpio_dt_alloc_pin() - Get an allocated GPIO instance from its DT phandle
1394fc179b6SThomas Perrot  *
140*8fd620f7SEtienne Carriere  * @pargs: Pointer to devicetree description of the GPIO controller to parse
1414fc179b6SThomas Perrot  * @res: Output result code of the operation:
1424fc179b6SThomas Perrot  *	TEE_SUCCESS in case of success
1434fc179b6SThomas Perrot  *	TEE_ERROR_DEFER_DRIVER_INIT if GPIO controller is not initialized
1444fc179b6SThomas Perrot  *	Any TEE_Result compliant code in case of error.
1454fc179b6SThomas Perrot  *
1464fc179b6SThomas Perrot  * Returns a struct gpio pointer pointing to a GPIO instance matching
1474fc179b6SThomas Perrot  * the devicetree description or NULL if invalid description in which case
1484fc179b6SThomas Perrot  * @res provides the error code.
1494fc179b6SThomas Perrot  */
150*8fd620f7SEtienne Carriere struct gpio *gpio_dt_alloc_pin(struct dt_pargs *pargs, TEE_Result *res);
1514fc179b6SThomas Perrot 
1524fc179b6SThomas Perrot /**
1534fc179b6SThomas Perrot  * gpio_dt_get_by_index() - Get a GPIO controller at a specific index in
1544fc179b6SThomas Perrot  * 'gpios' property
1554fc179b6SThomas Perrot  *
1564fc179b6SThomas Perrot  * @fdt: Device tree to work on
1574fc179b6SThomas Perrot  * @nodeoffset: Node offset of the subnode containing a 'gpios' property
1584fc179b6SThomas Perrot  * @index: GPIO pin index in '*-gpios' property
1594fc179b6SThomas Perrot  * @gpio_name: Name of the GPIO pin
1604fc179b6SThomas Perrot  * @gpio: Output GPIO pin reference upon success
1614fc179b6SThomas Perrot  *
1624fc179b6SThomas Perrot  * Return TEE_SUCCESS in case of success
1634fc179b6SThomas Perrot  * Return TEE_ERROR_DEFER_DRIVER_INIT if GPIO controller is not initialized
1644fc179b6SThomas Perrot  * Return a TEE_Result compliant code in case of error
1654fc179b6SThomas Perrot  */
1664fc179b6SThomas Perrot TEE_Result gpio_dt_get_by_index(const void *fdt, int nodeoffset,
1674fc179b6SThomas Perrot 				unsigned int index, const char *gpio_name,
1684fc179b6SThomas Perrot 				struct gpio **gpio);
1694fc179b6SThomas Perrot #else
1704fc179b6SThomas Perrot static inline TEE_Result gpio_dt_get_by_index(const void *fdt __unused,
1714fc179b6SThomas Perrot 					      int nodeoffset __unused,
1724fc179b6SThomas Perrot 					      unsigned int index  __unused,
1734fc179b6SThomas Perrot 					      const char *gpio_name  __unused,
1744fc179b6SThomas Perrot 					      struct gpio **gpio)
1754fc179b6SThomas Perrot {
1764fc179b6SThomas Perrot 	*gpio = NULL;
1774fc179b6SThomas Perrot 	return TEE_ERROR_NOT_SUPPORTED;
1784fc179b6SThomas Perrot }
1794fc179b6SThomas Perrot 
180*8fd620f7SEtienne Carriere static inline struct gpio *gpio_dt_alloc_pin(struct dt_pargs *pargs __unused,
1814fc179b6SThomas Perrot 					     TEE_Result *res)
1824fc179b6SThomas Perrot {
1834fc179b6SThomas Perrot 	*res = TEE_ERROR_NOT_SUPPORTED;
1844fc179b6SThomas Perrot 	return NULL;
1854fc179b6SThomas Perrot }
1864fc179b6SThomas Perrot #endif /*CFG_DT*/
1874fc179b6SThomas Perrot 
1884fc179b6SThomas Perrot /**
1894fc179b6SThomas Perrot  * gpio_dt_get_func - Typedef of function to get GPIO instance from
1904fc179b6SThomas Perrot  * devicetree properties
1914fc179b6SThomas Perrot  *
192*8fd620f7SEtienne Carriere  * @pargs: Pointer to GPIO phandle and its argument in the FDT
1934fc179b6SThomas Perrot  * @data: Pointer to the data given at gpio_dt_register_provider() call
1944fc179b6SThomas Perrot  * @res: Output result code of the operation:
1954fc179b6SThomas Perrot  *	TEE_SUCCESS in case of success
1964fc179b6SThomas Perrot  *	TEE_ERROR_DEFER_DRIVER_INIT if GPIO controller is not initialized
1974fc179b6SThomas Perrot  *	Any TEE_Result compliant code in case of error.
1984fc179b6SThomas Perrot  *
1994fc179b6SThomas Perrot  * Returns a struct GPIO pointer pointing to a GPIO instance matching
2004fc179b6SThomas Perrot  * the devicetree description or NULL if invalid description in which case
2014fc179b6SThomas Perrot  * @res provides the error code.
2024fc179b6SThomas Perrot  */
203*8fd620f7SEtienne Carriere typedef struct gpio *(*gpio_dt_get_func)(struct dt_pargs *pargs, void *data,
204*8fd620f7SEtienne Carriere 					 TEE_Result *res);
2054fc179b6SThomas Perrot 
2064fc179b6SThomas Perrot /**
2074fc179b6SThomas Perrot  * gpio_dt_register_provider() - Register a GPIO controller provider
2084fc179b6SThomas Perrot  *
2094fc179b6SThomas Perrot  * @fdt: Device tree to work on
2104fc179b6SThomas Perrot  * @nodeoffset: Node offset of the GPIO controller
2114fc179b6SThomas Perrot  * @get_dt_gpio: Callback to match the GPIO controller with a struct gpio
2124fc179b6SThomas Perrot  * @data: Opaque reference which will be passed to the get_dt_gpio callback
2134fc179b6SThomas Perrot  * Returns TEE_Result value
2144fc179b6SThomas Perrot  */
2154fc179b6SThomas Perrot static inline TEE_Result gpio_register_provider(const void *fdt, int nodeoffset,
2164fc179b6SThomas Perrot 						gpio_dt_get_func get_dt_gpio,
2174fc179b6SThomas Perrot 						void *data)
2184fc179b6SThomas Perrot {
2194fc179b6SThomas Perrot 	return dt_driver_register_provider(fdt, nodeoffset,
2204fc179b6SThomas Perrot 					   (get_of_device_func)get_dt_gpio,
2214fc179b6SThomas Perrot 					   data, DT_DRIVER_GPIO);
2224fc179b6SThomas Perrot }
2234fc179b6SThomas Perrot 
2246dcd18c8SClément Léger #endif	/* DRIVERS_GPIO_H */
225