Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | /* * Copyright (c) 2016 Linaro Limited * * SPDX-License-Identifier: Apache-2.0 */ #include <kernel.h> #include <board.h> #include <device.h> #include <errno.h> #include <init.h> #include <pinmux.h> #include <soc.h> #include <gpio/gpio_cmsdk_ahb.h> #include <misc/util.h> /* Number of pins for each port */ #define PINS_PER_PORT 16 #define CMSDK_AHB_GPIO0_DEV \ ((volatile struct gpio_cmsdk_ahb *)CMSDK_AHB_GPIO0) #define CMSDK_AHB_GPIO1_DEV \ ((volatile struct gpio_cmsdk_ahb *)CMSDK_AHB_GPIO1) static volatile struct gpio_cmsdk_ahb *_get_port(uint32_t pin) { uint32_t port_num = pin / PINS_PER_PORT; /* Port 2 and 3 are reserved therefore not handled in this driver */ switch (port_num) { case 0: return CMSDK_AHB_GPIO0_DEV; case 1: return CMSDK_AHB_GPIO1_DEV; default: /* return null if pin is outside range */ return NULL; } } static int pinmux_set(struct device *dev, uint32_t pin, uint32_t func) { volatile struct gpio_cmsdk_ahb *port = _get_port(pin); uint32_t tmp; uint32_t key; ARG_UNUSED(dev); if (!port) { return -EINVAL; } if (func) { /* * The irq_lock() here is required to prevent concurrent callers * to corrupt the pin functions. */ key = irq_lock(); tmp = port->altfuncset; tmp |= (1 << (pin % PINS_PER_PORT)); port->altfuncset = tmp; irq_unlock(key); } else { /* * The irq_lock() here is required to prevent concurrent callers * to corrupt the pin functions. */ key = irq_lock(); tmp = port->altfuncclr; tmp |= (1 << (pin % PINS_PER_PORT)); port->altfuncclr = tmp; irq_unlock(key); } return 0; } static int pinmux_get(struct device *dev, uint32_t pin, uint32_t *func) { volatile struct gpio_cmsdk_ahb *port = _get_port(pin); ARG_UNUSED(dev); if (!port) { return -EINVAL; } *func = (port->altfuncset & (1 << (pin % PINS_PER_PORT))) ? 1 : 0; return 0; } static int pinmux_pullup(struct device *dev, uint32_t pin, uint8_t func) { ARG_UNUSED(dev); ARG_UNUSED(pin); ARG_UNUSED(func); /* Beetle does not support programmable internal Pull-up/pull-down * on IO Pads. */ return 0; } static int pinmux_input(struct device *dev, uint32_t pin, uint8_t func) { volatile struct gpio_cmsdk_ahb *port = _get_port(pin); ARG_UNUSED(dev); if (!port) { return -EINVAL; } if (func) { port->outenableset = (1 << (pin % PINS_PER_PORT)); } else { port->outenableclr = (1 << (pin % PINS_PER_PORT)); } return 0; } static struct pinmux_driver_api api_funcs = { .set = pinmux_set, .get = pinmux_get, .pullup = pinmux_pullup, .input = pinmux_input }; static int pinmux_dev_init(struct device *port) { ARG_UNUSED(port); return 0; } DEVICE_AND_API_INIT(pmux_dev, CONFIG_PINMUX_DEV_NAME, &pinmux_dev_init, NULL, NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &api_funcs); |