/* * Copyright (C) 2025 Michael Brown . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * You can also choose to distribute this program under the terms of * the Unmodified Binary Distribution Licence (as given in the file * COPYING.UBDL), provided that you have satisfied its requirements. */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include /** @file * * General purpose I/O * */ /** List of GPIO controllers */ static LIST_HEAD ( all_gpios ); /** * Allocate GPIO controller * * @v count Number of GPIO pins * @v priv_len Size of driver-private data * @ret gpios GPIO controller, or NULL */ struct gpios * alloc_gpios ( unsigned int count, size_t priv_len ) { struct gpios *gpios; struct gpio *gpio; size_t len; unsigned int i; /* Allocate and initialise structure */ len = ( sizeof ( *gpios ) + ( count * sizeof ( *gpio ) ) + priv_len ); gpios = zalloc ( len ); if ( ! gpios ) return NULL; gpios->count = count; gpios->gpio = ( ( ( void * ) gpios ) + sizeof ( *gpios ) ); gpios->priv = ( ( ( void * ) gpios ) + sizeof ( *gpios ) + ( count * sizeof ( *gpio ) ) ); /* Initialise GPIO pins */ for ( i = 0 ; i < count ; i++ ) { gpio = &gpios->gpio[i]; gpio->gpios = gpios; gpio->index = i; } return gpios; } /** * Register GPIO controller * * @v gpios GPIO controller * @ret rc Return status code */ int gpios_register ( struct gpios *gpios ) { /* Add to list of GPIO controllers */ gpios_get ( gpios ); list_add_tail ( &gpios->list, &all_gpios ); DBGC ( gpios, "GPIO %s registered with %d GPIOs\n", gpios->dev->name, gpios->count ); return 0; } /** * Unregister GPIO controller * * @v gpios GPIO controller */ void gpios_unregister ( struct gpios *gpios ) { /* Remove from list of GPIO controllers */ DBGC ( gpios, "GPIO %s unregistered\n", gpios->dev->name ); list_del ( &gpios->list ); gpios_put ( gpios ); } /** * Find GPIO controller * * @v bus_type Bus type * @v location Bus location * @ret gpios GPIO controller, or NULL */ struct gpios * gpios_find ( unsigned int bus_type, unsigned int location ) { struct gpios *gpios; /* Scan through list of registered GPIO controllers */ list_for_each_entry ( gpios, &all_gpios, list ) { if ( ( gpios->dev->desc.bus_type == bus_type ) && ( gpios->dev->desc.location == location ) ) return gpios; } return NULL; } /** * Get null GPIO input value * * @v gpios GPIO controller * @v gpio GPIO pin * @ret active Pin is in the active state */ static int null_gpio_in ( struct gpios *gpios __unused, struct gpio *gpio __unused ) { return 0; } /** * Set null GPIO output value * * @v gpios GPIO controller * @v gpio GPIO pin * @v active Set pin to active state */ static void null_gpio_out ( struct gpios *gpios __unused, struct gpio *gpio __unused, int active __unused ) { /* Nothing to do */ } /** * Configure null GPIO pin * * @v gpios GPIO controller * @v gpio GPIO pin * @v config Configuration * @ret rc Return status code */ static int null_gpio_config ( struct gpios *gpios __unused, struct gpio *gpio __unused, unsigned int config __unused ) { return -ENODEV; } /** Null GPIO operations */ struct gpio_operations null_gpio_operations = { .in = null_gpio_in, .out = null_gpio_out, .config = null_gpio_config, };