pinmux/stm32: add common driver for STM32 pinmux

Add a common driver for pin control subsystem in STM32 MCU series. The
driver allows for selection of pin's function without the ability of pin
remapping.

The driver implements a pinmux driver API, with custom `func` and `pin`
encoding in API calls. The caller is expected to use STM32PIN() helper
macro for encoding port/pin numbers or using one of the provided
STM32_PIN_* defines.

The common driver requires SoC specific support to be implemented. The
SoC code must implement these calls: stm32_get_pin_config(),
stm32_get_port_clock(), stm32_pin_configure(). Consult pinmux_stm32.h
header for detailn on semantics of these calls.

The driver also requires board level integration. The call
stm32_board_get_pinconf() is expected to privide pin function
assignments for the target board.

Whenever an IO pin is being enabled, the driver will automatically
enable the clock for corresponding port. The driver does not implement
disabling of port's clock as this has potentially disruptive, as such
such operation should be done explicitly in the code.

The pin control module needs to be initialized before any other modules,
but after clock_control. For this reason, the driver is initialized by
default at PRIMARY level, with priority set to 2. The priority can be
changed through configuration.

Change-Id: I8cb746d0f3cad72cd50b3355fe6d93a9f469be25
Origin: Original
Signed-off-by: Maciej Borzecki <maciek.borzecki@gmail.com>
This commit is contained in:
Maciek Borzecki 2016-03-03 15:33:15 +01:00
commit e53390f02d
5 changed files with 480 additions and 0 deletions

View file

@ -149,3 +149,4 @@ config PINMUX_K64_GPIO_E_NAME
help help
The name of the Port E GPIO referred to as PTE0..PTE31. The name of the Port E GPIO referred to as PTE0..PTE31.
source "drivers/pinmux/Kconfig.stm32"

View file

@ -0,0 +1,33 @@
# Kconfig - configuration for STM32 pinmux
#
# Copyright (c) 2016 Open-RnD Sp. z o.o.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
config PINMUX_STM32
bool "Pinmux driver for STM32 MCUs"
depends on PINMUX && SOC_STM32
help
Enable pin multiplexter for STM32 MCUs
config PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY
int "Device initialization priority STM32 pinmux"
depends on PINMUX_STM32
default 2
help
This option controls the priority of pinmux device initialization.
Higher priority ensures that the device is initialized earlier in
the startup cycle. Note that the pinmux device needs to be initialized
after clock control device, but possibly before all other devices.
If unsure, leave at default value 2

View file

@ -1,3 +1,4 @@
ccflags-y +=-I$(srctree)/drivers ccflags-y +=-I$(srctree)/drivers
obj-$(CONFIG_PINMUX_K64) += pinmux_k64.o obj-$(CONFIG_PINMUX_K64) += pinmux_k64.o
obj-$(CONFIG_PINMUX_STM32) += pinmux_stm32.o

View file

@ -0,0 +1,162 @@
/*
* Copyright (c) 2016 Open-RnD Sp. z o.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @brief
*
* A common driver for STM32 pinmux. Each SoC must implement a SoC
* specific part of the driver.
*/
#include <nanokernel.h>
#include <device.h>
#include <soc.h>
#include "pinmux.h"
#include <pinmux.h>
#include <pinmux/pinmux_stm32.h>
#include <clock_control/stm32_clock_control.h>
/**
* @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)
{
clock_control_subsys_t subsys = stm32_get_port_clock(port);
/* enable port clock */
if (!clk) {
clk = device_get_binding(STM32_CLOCK_CONTROL_NAME);
}
return clock_control_on(clk, subsys);
}
/**
* @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
*/
static inline 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);
}
static int pinmux_stm32_set(struct device *dev,
uint32_t pin, uint32_t func)
{
ARG_UNUSED(dev);
return __pinmux_stm32_set(pin, func, NULL);
}
static int pinmux_stm32_get(struct device *dev,
uint32_t pin, uint32_t *func)
{
return -ENOTSUP;
}
static int pinmux_stm32_input(struct device *dev,
uint32_t pin,
uint8_t func)
{
return -ENOTSUP;
}
static int pinmux_stm32_pullup(struct device *dev,
uint32_t pin,
uint8_t func)
{
return -ENOTSUP;
}
static struct pinmux_driver_api pinmux_stm32_api = {
.set = pinmux_stm32_set,
.get = pinmux_stm32_get,
.pullup = pinmux_stm32_pullup,
.input = pinmux_stm32_input,
};
/**
* @brief setup pins according to their assignments
*
* @param pinconf board pin configuration array
* @param pins array size
*/
static inline void __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);
}
}
int pinmux_stm32_init(struct device *port)
{
size_t pins = 0;
const struct pin_config *pinconf;
pinconf = stm32_board_get_pinconf(&pins);
if (pins != 0) {
/* configure pins */
__setup_pins(pinconf, pins);
}
port->driver_api = &pinmux_stm32_api;
return 0;
}
static struct pinmux_config pinmux_stm32_cfg = {
#ifdef CONFIG_SOC_STM32F1X
.base_address = GPIO_PORTS_BASE,
#endif
};
/**
* @brief device init
*
* Device priority set to 2, so that we come after clock_control and
* before any other devices
*/
DEVICE_INIT(pinmux_stm32, STM32_PINMUX_NAME, &pinmux_stm32_init,
NULL, &pinmux_stm32_cfg,
PRIMARY, CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY);

View file

@ -0,0 +1,283 @@
/*
* Copyright (c) 2016 Open-RnD Sp. z o.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file header for STM32 pin multiplexing
*/
#ifndef _STM32_PINMUX_H_
#define _STM32_PINMUX_H_
#include <stdint.h>
#include <stddef.h>
#include <clock_control.h>
#include "pinmux.h"
/**
* @brief numerical IDs for IO ports
*/
enum stm32_pin_port {
STM32_PORTA = 0, /* IO port A */
STM32_PORTB, /* .. */
STM32_PORTC,
STM32_PORTD,
STM32_PORTE,
STM32_PORTF,
STM32_PORTG,
STM32_PORTH, /* IO port H */
};
/* override this at soc level */
#ifndef STM32_PORTS_MAX
#define STM32_PORTS_MAX (STM32_PORTH + 1)
#endif
/**
* @brief helper macro to encode an IO port pin in a numerical format
*/
#define STM32PIN(_port, _pin) \
(_port << 4 | _pin)
/*
*/
enum stm32_pin_alt_func {
STM32_PINMUX_FUNC_ALT_0 = 0, /* GPIO */
STM32_PINMUX_FUNC_ALT_1,
STM32_PINMUX_FUNC_ALT_2,
STM32_PINMUX_FUNC_ALT_3,
STM32_PINMUX_FUNC_ALT_4,
STM32_PINMUX_FUNC_ALT_5,
STM32_PINMUX_FUNC_ALT_6,
STM32_PINMUX_FUNC_ALT_7,
STM32_PINMUX_FUNC_ALT_MAX
};
#define STM32_PINMUX_FUNC_GPIO 0
#define STM32_PINMUX_FUNC_ANALOG (STM32_PINMUX_FUNC_ALT_MAX)
#define STM32_PIN_PA0 STM32PIN(STM32_PORTA, 0)
#define STM32_PIN_PA1 STM32PIN(STM32_PORTA, 1)
#define STM32_PIN_PA2 STM32PIN(STM32_PORTA, 2)
#define STM32_PIN_PA3 STM32PIN(STM32_PORTA, 3)
#define STM32_PIN_PA4 STM32PIN(STM32_PORTA, 4)
#define STM32_PIN_PA5 STM32PIN(STM32_PORTA, 5)
#define STM32_PIN_PA6 STM32PIN(STM32_PORTA, 6)
#define STM32_PIN_PA7 STM32PIN(STM32_PORTA, 7)
#define STM32_PIN_PA8 STM32PIN(STM32_PORTA, 8)
#define STM32_PIN_PA9 STM32PIN(STM32_PORTA, 9)
#define STM32_PIN_PA10 STM32PIN(STM32_PORTA, 10)
#define STM32_PIN_PA11 STM32PIN(STM32_PORTA, 11)
#define STM32_PIN_PA12 STM32PIN(STM32_PORTA, 12)
#define STM32_PIN_PA13 STM32PIN(STM32_PORTA, 13)
#define STM32_PIN_PA14 STM32PIN(STM32_PORTA, 14)
#define STM32_PIN_PA15 STM32PIN(STM32_PORTA, 15)
#define STM32_PIN_PB0 STM32PIN(STM32_PORTB, 0)
#define STM32_PIN_PB1 STM32PIN(STM32_PORTB, 1)
#define STM32_PIN_PB2 STM32PIN(STM32_PORTB, 2)
#define STM32_PIN_PB3 STM32PIN(STM32_PORTB, 3)
#define STM32_PIN_PB4 STM32PIN(STM32_PORTB, 4)
#define STM32_PIN_PB5 STM32PIN(STM32_PORTB, 5)
#define STM32_PIN_PB6 STM32PIN(STM32_PORTB, 6)
#define STM32_PIN_PB7 STM32PIN(STM32_PORTB, 7)
#define STM32_PIN_PB8 STM32PIN(STM32_PORTB, 8)
#define STM32_PIN_PB9 STM32PIN(STM32_PORTB, 9)
#define STM32_PIN_PB10 STM32PIN(STM32_PORTB, 10)
#define STM32_PIN_PB11 STM32PIN(STM32_PORTB, 11)
#define STM32_PIN_PB12 STM32PIN(STM32_PORTB, 12)
#define STM32_PIN_PB13 STM32PIN(STM32_PORTB, 13)
#define STM32_PIN_PB14 STM32PIN(STM32_PORTB, 14)
#define STM32_PIN_PB15 STM32PIN(STM32_PORTB, 15)
#define STM32_PIN_PC0 STM32PIN(STM32_PORTC, 0)
#define STM32_PIN_PC1 STM32PIN(STM32_PORTC, 1)
#define STM32_PIN_PC2 STM32PIN(STM32_PORTC, 2)
#define STM32_PIN_PC3 STM32PIN(STM32_PORTC, 3)
#define STM32_PIN_PC4 STM32PIN(STM32_PORTC, 4)
#define STM32_PIN_PC5 STM32PIN(STM32_PORTC, 5)
#define STM32_PIN_PC6 STM32PIN(STM32_PORTC, 6)
#define STM32_PIN_PC7 STM32PIN(STM32_PORTC, 7)
#define STM32_PIN_PC8 STM32PIN(STM32_PORTC, 8)
#define STM32_PIN_PC9 STM32PIN(STM32_PORTC, 9)
#define STM32_PIN_PC10 STM32PIN(STM32_PORTC, 10)
#define STM32_PIN_PC11 STM32PIN(STM32_PORTC, 11)
#define STM32_PIN_PC12 STM32PIN(STM32_PORTC, 12)
#define STM32_PIN_PC13 STM32PIN(STM32_PORTC, 13)
#define STM32_PIN_PC14 STM32PIN(STM32_PORTC, 14)
#define STM32_PIN_PC15 STM32PIN(STM32_PORTC, 15)
#define STM32_PIN_PD0 STM32PIN(STM32_PORTD, 0)
#define STM32_PIN_PD1 STM32PIN(STM32_PORTD, 1)
#define STM32_PIN_PD2 STM32PIN(STM32_PORTD, 2)
#define STM32_PIN_PD3 STM32PIN(STM32_PORTD, 3)
#define STM32_PIN_PD4 STM32PIN(STM32_PORTD, 4)
#define STM32_PIN_PD5 STM32PIN(STM32_PORTD, 5)
#define STM32_PIN_PD6 STM32PIN(STM32_PORTD, 6)
#define STM32_PIN_PD7 STM32PIN(STM32_PORTD, 7)
#define STM32_PIN_PD8 STM32PIN(STM32_PORTD, 8)
#define STM32_PIN_PD9 STM32PIN(STM32_PORTD, 9)
#define STM32_PIN_PD10 STM32PIN(STM32_PORTD, 10)
#define STM32_PIN_PD11 STM32PIN(STM32_PORTD, 11)
#define STM32_PIN_PD12 STM32PIN(STM32_PORTD, 12)
#define STM32_PIN_PD13 STM32PIN(STM32_PORTD, 13)
#define STM32_PIN_PD14 STM32PIN(STM32_PORTD, 14)
#define STM32_PIN_PD15 STM32PIN(STM32_PORTD, 15)
#define STM32_PIN_PE0 STM32PIN(STM32_PORTE, 0)
#define STM32_PIN_PE1 STM32PIN(STM32_PORTE, 1)
#define STM32_PIN_PE2 STM32PIN(STM32_PORTE, 2)
#define STM32_PIN_PE3 STM32PIN(STM32_PORTE, 3)
#define STM32_PIN_PE4 STM32PIN(STM32_PORTE, 4)
#define STM32_PIN_PE5 STM32PIN(STM32_PORTE, 5)
#define STM32_PIN_PE6 STM32PIN(STM32_PORTE, 6)
#define STM32_PIN_PE7 STM32PIN(STM32_PORTE, 7)
#define STM32_PIN_PE8 STM32PIN(STM32_PORTE, 8)
#define STM32_PIN_PE9 STM32PIN(STM32_PORTE, 9)
#define STM32_PIN_PE10 STM32PIN(STM32_PORTE, 10)
#define STM32_PIN_PE11 STM32PIN(STM32_PORTE, 11)
#define STM32_PIN_PE12 STM32PIN(STM32_PORTE, 12)
#define STM32_PIN_PE13 STM32PIN(STM32_PORTE, 13)
#define STM32_PIN_PE14 STM32PIN(STM32_PORTE, 14)
#define STM32_PIN_PE15 STM32PIN(STM32_PORTE, 15)
#define STM32_PIN_PF0 STM32PIN(STM32_PORTF, 0)
#define STM32_PIN_PF1 STM32PIN(STM32_PORTF, 1)
#define STM32_PIN_PF2 STM32PIN(STM32_PORTF, 2)
#define STM32_PIN_PF3 STM32PIN(STM32_PORTF, 3)
#define STM32_PIN_PF4 STM32PIN(STM32_PORTF, 4)
#define STM32_PIN_PF5 STM32PIN(STM32_PORTF, 5)
#define STM32_PIN_PF6 STM32PIN(STM32_PORTF, 6)
#define STM32_PIN_PF7 STM32PIN(STM32_PORTF, 7)
#define STM32_PIN_PF8 STM32PIN(STM32_PORTF, 8)
#define STM32_PIN_PF9 STM32PIN(STM32_PORTF, 9)
#define STM32_PIN_PF10 STM32PIN(STM32_PORTF, 10)
#define STM32_PIN_PF11 STM32PIN(STM32_PORTF, 11)
#define STM32_PIN_PF12 STM32PIN(STM32_PORTF, 12)
#define STM32_PIN_PF13 STM32PIN(STM32_PORTF, 13)
#define STM32_PIN_PF14 STM32PIN(STM32_PORTF, 14)
#define STM32_PIN_PF15 STM32PIN(STM32_PORTF, 15)
#define STM32_PIN_PG0 STM32PIN(STM32_PORTG, 0)
#define STM32_PIN_PG1 STM32PIN(STM32_PORTG, 1)
#define STM32_PIN_PG2 STM32PIN(STM32_PORTG, 2)
#define STM32_PIN_PG3 STM32PIN(STM32_PORTG, 3)
#define STM32_PIN_PG4 STM32PIN(STM32_PORTG, 4)
#define STM32_PIN_PG5 STM32PIN(STM32_PORTG, 5)
#define STM32_PIN_PG6 STM32PIN(STM32_PORTG, 6)
#define STM32_PIN_PG7 STM32PIN(STM32_PORTG, 7)
#define STM32_PIN_PG8 STM32PIN(STM32_PORTG, 8)
#define STM32_PIN_PG9 STM32PIN(STM32_PORTG, 9)
#define STM32_PIN_PG10 STM32PIN(STM32_PORTG, 10)
#define STM32_PIN_PG11 STM32PIN(STM32_PORTG, 11)
#define STM32_PIN_PG12 STM32PIN(STM32_PORTG, 12)
#define STM32_PIN_PG13 STM32PIN(STM32_PORTG, 13)
#define STM32_PIN_PG14 STM32PIN(STM32_PORTG, 14)
#define STM32_PIN_PG15 STM32PIN(STM32_PORTG, 15)
/* pretend that array will cover pin functions */
typedef int stm32_pin_func_t;
/**
* @brief pinmux config wrapper
*
* GPIO function is assumed to be always available, as such it's not listed
* in @funcs array
*/
struct stm32_pinmux_conf {
uint32_t pin; /* pin ID */
const stm32_pin_func_t *funcs; /* functions array, indexed with
* (stm32_pin_alt_func - 1)
*/
const size_t nfuncs; /* number of alternate functions, not
* counting GPIO
*/
};
/**
* @brief helper to define pins
*/
#define STM32_PIN_CONF(__pin, __funcs) \
{__pin, __funcs, ARRAY_SIZE(__funcs)}
/**
* @brief helper to extract IO port number from STM32PIN() encoded
* value
*/
#define STM32_PORT(__pin) \
(__pin >> 4)
/**
* @brief helper to extract IO pin number from STM32PIN() encoded
* value
*/
#define STM32_PIN(__pin) \
(__pin & 0xf)
/**
* @brief helper for mapping pin function to its configuration
*
* @param pin pin ID encoded with STM32PIN()
* @param func alternate function ID
*
* Helper function for mapping alternate function for given pin to its
* configuration. This function must be implemented by SoC integartion
* code.
*
* @return SoC specific pin configuration
*/
int stm32_get_pin_config(int pin, int func);
/**
* @brief helper for mapping IO port to its clock subsystem
*
* @param port IO port
*
* Map given IO @port to corresponding clock subsystem. The returned
* clock subsystemd ID must suitable for passing as parameter to
* clock_control_on(). Implement this function at the SoC level.
*
* @return clock subsystem ID
*/
clock_control_subsys_t stm32_get_port_clock(int port);
/**
* @brief helper for configuration of IO pin
*
* @param pin IO pin, STM32PIN() encoded
* @param func IO function encoded
*/
int stm32_pin_configure(int pin, int func);
/**
* @brief helper for obtaining pin configuration for the board
*
* @param[out] pins set to the number of pins in the array
*
* Obtain pin assignment/configuration for current board. This call
* needs to be implemented at the board integration level. After
* restart all pins are already configured as GPIO and can be skipped
* in the configuration arrray. Pin numbers in @pin_num field are
* STM32PIN() encoded.
*
* @return array of pin assignments
*/
const struct pin_config *stm32_board_get_pinconf(size_t *pins);
/* common pinmux device name for all STM32 chips */
#define STM32_PINMUX_NAME "stm32-pinmux"
#endif /* _STM32_PINMUX_H_ */