summaryrefslogtreecommitdiff
path: root/drivers/pinmux/stm32/pinmux_stm32.c
blob: 325c76b071827f80f4e5ebfb9518af5dce64bdbb (plain)
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
146
147
148
149
150
151
152
153
154
155
/*
 * Copyright (c) 2016 Open-RnD Sp. z o.o.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @brief
 *
 * A common driver for STM32 pinmux. Each SoC must implement a SoC
 * specific part of the driver.
 */

#include <errno.h>

#include <kernel.h>
#include <device.h>
#include <soc.h>
#include <pinmux.h>
#include <gpio/gpio_stm32.h>
#include <clock_control/stm32_clock_control.h>
#include <pinmux/stm32/pinmux_stm32.h>

#include "pinmux.h"

#if defined(CONFIG_CLOCK_CONTROL_STM32_CUBE)
static const uint32_t ports_enable[STM32_PORTS_MAX] = {
	STM32_PERIPH_GPIOA,
	STM32_PERIPH_GPIOB,
	STM32_PERIPH_GPIOC,
	STM32_PERIPH_GPIOD,
#ifdef GPIOE_BASE
	STM32_PERIPH_GPIOE,
#endif
#ifdef GPIOF_BASE
	STM32_PERIPH_GPIOF,
#endif
#ifdef GPIOG_BASE
	STM32_PERIPH_GPIOG,
#endif
#ifdef GPIOH_BASE
	STM32_PERIPH_GPIOH,
#endif
};
#elif defined(CONFIG_SOC_SERIES_STM32F4X)
static const uint32_t ports_enable[STM32_PORTS_MAX] = {
	STM32F4X_CLOCK_ENABLE_GPIOA,
	STM32F4X_CLOCK_ENABLE_GPIOB,
	STM32F4X_CLOCK_ENABLE_GPIOC,
	STM32F4X_CLOCK_ENABLE_GPIOD,
	STM32F4X_CLOCK_ENABLE_GPIOE,
	STM32F4X_CLOCK_ENABLE_GPIOF,
	STM32F4X_CLOCK_ENABLE_GPIOG,
	STM32F4X_CLOCK_ENABLE_GPIOH,
};
#endif

/**
 * @brief enable IO port clock
 *
 * @param port I/O port ID
 * @param clk  optional clock device
 *
 * @return 0 on success, error otherwise
 */
static int enable_port(uint32_t port, struct device *clk)
{
	/* enable port clock */
	if (!clk) {
		clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);
	}

	/* TODO: Merge this and move the port clock to the soc file */
#if defined(CONFIG_CLOCK_CONTROL_STM32_CUBE)
	struct stm32_pclken pclken;

	pclken.bus = STM32_CLOCK_BUS_GPIO;
	pclken.enr = ports_enable[port];

	return clock_control_on(clk, (clock_control_subsys_t *) &pclken);
#else
#if defined(CONFIG_SOC_SERIES_STM32F1X) || \
	defined(CONFIG_SOC_SERIES_STM32F3X) || \
	defined(CONFIG_SOC_SERIES_STM32L4X)
	clock_control_subsys_t subsys = stm32_get_port_clock(port);

	return clock_control_on(clk, subsys);
#elif CONFIG_SOC_SERIES_STM32F4X
	struct stm32f4x_pclken pclken;
	/* AHB1 bus for all the GPIO ports */
	pclken.bus = STM32F4X_CLOCK_BUS_AHB1;
	pclken.enr = ports_enable[port];

	return clock_control_on(clk, (clock_control_subsys_t *) &pclken);
#endif
#endif /* CONFIG_CLOCK_CONTROL_STM32_CUBE */
}

static int stm32_pin_configure(int pin, int func, int altf)
{
	/* determine IO port registers location */
	uint32_t offset = STM32_PORT(pin) * GPIO_REG_SIZE;
	uint8_t *port_base = (uint8_t *)(GPIO_PORTS_BASE + offset);

	/* not much here, on STM32F10x the alternate function is
	 * controller by setting up GPIO pins in specific mode.
	 */
	return stm32_gpio_configure((uint32_t *)port_base,
				    STM32_PIN(pin), func, altf);
}

/**
 * @brief pin setup
 *
 * @param pin  STM32PIN() encoded pin ID
 * @param func SoC specific function assignment
 * @param clk  optional clock device
 *
 * @return 0 on success, error otherwise
 */
int _pinmux_stm32_set(uint32_t pin, uint32_t func,
				struct device *clk)
{
	int config;

	/* make sure to enable port clock first */
	if (enable_port(STM32_PORT(pin), clk)) {
		return -EIO;
	}

	/* determine config for alternate function */
	config = stm32_get_pin_config(pin, func);

	return stm32_pin_configure(pin, config, func);
}

/**
 * @brief setup pins according to their assignments
 *
 * @param pinconf  board pin configuration array
 * @param pins     array size
 */
void stm32_setup_pins(const struct pin_config *pinconf,
		      size_t pins)
{
	struct device *clk;
	int i;

	clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);

	for (i = 0; i < pins; i++) {
		_pinmux_stm32_set(pinconf[i].pin_num,
				  pinconf[i].mode, clk);
	}
}