zephyr/boards/arduino_due/pinmux_due.c

439 lines
9.2 KiB
C

/*
* Copyright (c) 2016 Intel Corporation
*
* 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.
*/
#include <nanokernel.h>
#include <board.h>
#include <device.h>
#include <init.h>
#include <pinmux.h>
#include <misc/util.h>
/**
* @brief Pinmux driver for Arduino due
*
* The SAM3X8E on Arduion Due has 4 PIO controllers. These controllers
* are responsible for pin muxing, input/output, pull-up, etc.
*
* All PIO controller pins are flatten into sequentially incrementing
* pin numbers:
* Pins 0 - 31 are for PIOA
* Pins 32 - 63 are for PIOB
* Pins 64 - 95 are for PIOC
* Pins 96 - 127 are for PIOD
*
* For all the pin descriptions, refer to the Atmel datasheet, and
* the Arduino Due schematics.
*/
/*
* These is the mapping from the board pins to PIO controllers.
* This mapping is created from the Arduino Due schematics.
* Refer to the official schematics for the actual mapping,
* as the following may not be accurate.
*
* IO_0 : PA8
* IO_1 : PA9
* IO_2 : PB25
* IO_3 : PC28
* IO_4 : PA29
* IO_5 : PC25
* IO_6 : PC24
* IO_7 : PC23
*
* IO_8 : PC22
* IO_9 : PC21
* IO_10 : PA28 and PC29
* IO_11 : PD7
* IO_12 : PD8
* IO_13 : PB27
* SDA1 : PA17
* SCL1 : PA18
*
* IO_14 : PD4
* IO_15 : PD5
* IO_16 : PA13
* IO_17 : PA12
* IO_18 : PA11
* IO_19 : PA10
* IO_20 : PB12
* IO_21 : PB13
*
* A_0 : PA16
* A_1 : PA24
* A_2 : PA23
* A_3 : PA22
* A_4 : PA6
* A_5 : PA4
* A_6 : PA3
* A_7 : PA2
*
* A_8 : PB17
* A_9 : PB18
* A_10 : PB19
* A_11 : PB20
* DAC0 : PB15
* DAC1 : PB16
* CANRX : PA1
* CANTX : PA0
*
* IO_22 : PB26
* IO_23 : PA14
* IO_24 : PA15
* IO_25 : PD0
* IO_26 : PD1
* IO_27 : PD2
* IO_28 : PD3
* IO_29 : PD6
* IO_30 : PD9
* IO_31 : PA7
* IO_32 : PD10
* IO_33 : PC1
* IO_34 : PC2
* IO_35 : PC3
* IO_36 : PC4
* IO_37 : PC5
* IO_38 : PC6
* IO_39 : PC7
* IO_40 : PC8
* IO_41 : PC9
* IO_42 : PA19
* IO_43 : PA20
* IO_44 : PC19
* IO_45 : PC18
* IO_46 : PC17
* IO_47 : PC16
* IO_48 : PC15
* IO_49 : PC14
* IO_50 : PC13
* IO_51 : PC12
*/
#ifndef CONFIG_PINMUX_DEV
#define PRINT(...) {; }
#else
#if defined(CONFIG_PRINTK)
#include <misc/printk.h>
#define PRINT printk
#elif defined(CONFIG_STDOUT_CONSOLE)
#define PRINT printf
#endif /* CONFIG_PRINTK */
#endif /*CONFIG_PINMUX_DEV */
static volatile struct __pio *_get_port(uint32_t pin)
{
uint32_t port_num = pin / 32;
switch (port_num) {
case 0:
return __PIOA;
case 1:
return __PIOB;
case 2:
return __PIOC;
case 3:
return __PIOD;
default:
/* return null if pin is outside range */
return NULL;
}
}
#ifdef CONFIG_PINMUX_DEV
static uint32_t pinmux_set(struct device *dev, uint32_t pin, uint32_t func)
{
volatile struct __pio *port = _get_port(pin);
uint32_t tmp;
ARG_UNUSED(dev);
if (!port) {
return DEV_INVALID_CONF;
}
tmp = port->absr;
if (func) {
tmp |= (1 << (pin % 32));
} else {
tmp &= ~(1 << (pin % 32));
}
port->absr = tmp;
return DEV_OK;
}
static uint32_t pinmux_get(struct device *dev, uint32_t pin, uint32_t *func)
{
volatile struct __pio *port = _get_port(pin);
ARG_UNUSED(dev);
if (!port) {
return DEV_INVALID_CONF;
}
*func = (port->absr & (1 << (pin % 32))) ? 1 : 0;
return DEV_OK;
}
#else
static uint32_t pinmux_set(struct device *dev, uint32_t pin, uint32_t func)
{
ARG_UNUSED(dev);
ARG_UNUSED(pin);
ARG_UNUSED(func);
PRINT("ERROR: %s is not enabled", __func__);
return DEV_NOT_CONFIG;
}
static uint32_t pinmux_get(struct device *dev, uint32_t pin, uint32_t *func)
{
ARG_UNUSED(dev);
ARG_UNUSED(pin);
ARG_UNUSED(func);
PRINT("ERROR: %s is not enabled", __func__);
return DEV_NOT_CONFIG;
}
#endif /* CONFIG_PINMUX_DEV */
static uint32_t pinmux_pullup(struct device *dev, uint32_t pin, uint8_t func)
{
volatile struct __pio *port = _get_port(pin);
ARG_UNUSED(dev);
if (!port) {
return DEV_INVALID_CONF;
}
if (func) {
port->puer = (1 << (pin % 32));
} else {
port->pudr = (1 << (pin % 32));
}
return DEV_OK;
}
static uint32_t pinmux_input(struct device *dev, uint32_t pin, uint8_t func)
{
volatile struct __pio *port = _get_port(pin);
ARG_UNUSED(dev);
if (!port) {
return DEV_INVALID_CONF;
}
if (func) {
port->odr = (1 << (pin % 32));
} else {
port->oer = (1 << (pin % 32));
}
return DEV_OK;
}
#define N_PIOA 0
#define N_PIOB 1
#define N_PIOC 2
#define N_PIOD 3
/*
* This function sets the default for the following:
* - Pin mux (peripheral A or B)
* - Set pin as input or output
* - Enable pull-up for pins
*
* At boot, all pins are outputs with pull-up enabled, and are set to be
* peripheral A (with value 0). So only the peripherals that need to be
* set to B (value 1) will be declared explicitly below.
*
* Note that all pins are set to be controlled by the PIO controllers
* by default. For peripherals to work (e.g. UART), the PIO has to
* be disabled for that pin (e.g. UART to take over those pins).
*/
static void __pinmux_defaults(void)
{
uint32_t ab_select[4]; /* A/B selection */
uint32_t output_en[4]; /* output enabled */
uint32_t pull_up[4]; /* pull-up enabled */
uint32_t pio_ctrl[4]; /* PIO enable */
uint32_t tmp;
/* Read defaults at boot, as the bootloader may have already
* configured some pins.
*/
ab_select[N_PIOA] = __PIOA->absr;
ab_select[N_PIOB] = __PIOB->absr;
ab_select[N_PIOC] = __PIOC->absr;
ab_select[N_PIOD] = __PIOD->absr;
output_en[N_PIOA] = __PIOA->osr;
output_en[N_PIOB] = __PIOB->osr;
output_en[N_PIOC] = __PIOC->osr;
output_en[N_PIOD] = __PIOD->osr;
pio_ctrl[N_PIOA] = __PIOA->psr;
pio_ctrl[N_PIOB] = __PIOB->psr;
pio_ctrl[N_PIOC] = __PIOC->psr;
pio_ctrl[N_PIOD] = __PIOD->psr;
/* value 1 means pull-up disabled, so need to invert */
pull_up[N_PIOA] = ~(__PIOA->pusr);
pull_up[N_PIOB] = ~(__PIOB->pusr);
pull_up[N_PIOC] = ~(__PIOC->pusr);
pull_up[N_PIOD] = ~(__PIOD->pusr);
/*
* Now modify as we wish
*/
/* Make sure JTAG pins are used for JTAG */
pio_ctrl[N_PIOB] &= ~(BIT(28) | BIT(29) | BIT(30) | BIT(31));
/* UART console:
* IO_0: PA8 (RX)
* IO_1: PA9 (TX)
*/
pio_ctrl[N_PIOA] &= ~(BIT(8) | BIT(9));
/* I2C pins on TWI controller #0
*
* SDA1: PA17
* SCL1: PA18
*
* Note that these need external pull-up resistors.
*/
pio_ctrl[N_PIOA] &= ~(BIT(17) | BIT(18));
/* I2C pins on TWI controller #1
*
* IO_20: PB12 (SDA)
* IO_21: PB13 (SCL)
*
* Board already have pull-up resistors.
*/
pio_ctrl[N_PIOB] &= ~(BIT(12) | BIT(13));
/*
* Setup ADC pins.
*
* Note that the ADC is considered extra function
* for the pins (other than A or B). This extra
* pin function is enabled by enabling the ADC
* controller. Therefore, the following code
* only sets these pins as input, with pull-up
* disabled. This does not detach the PIO
* controller from the pins so the peripherals
* won't take over.
*
* A_0 : PA16
* A_1 : PA24
* A_2 : PA23
* A_3 : PA22
* A_4 : PA6
* A_5 : PA4
* A_6 : PA3
* A_7 : PA2
*
* A_8 : PB17
* A_9 : PB18
* A_10: PB19
* A_11: PB20
*/
tmp = BIT(16) | BIT(24) | BIT(23) | BIT(22)
| BIT(6) | BIT(4) | BIT(3) | BIT(2);
pio_ctrl[N_PIOA] |= tmp;
output_en[N_PIOA] &= ~(tmp);
pull_up[N_PIOA] &= ~(tmp);
tmp = BIT(17) | BIT(18) | BIT(19) | BIT(20);
pio_ctrl[N_PIOB] |= tmp;
output_en[N_PIOB] &= ~(tmp);
pull_up[N_PIOB] &= ~(tmp);
/*
* Write modifications back to those registers
*/
__PIOA->absr = ab_select[N_PIOA];
__PIOB->absr = ab_select[N_PIOB];
__PIOC->absr = ab_select[N_PIOC];
__PIOD->absr = ab_select[N_PIOD];
/* set output enable */
__PIOA->oer = output_en[N_PIOA];
__PIOB->oer = output_en[N_PIOB];
__PIOC->oer = output_en[N_PIOC];
__PIOD->oer = output_en[N_PIOD];
/* set output disable */
__PIOA->odr = ~(output_en[N_PIOA]);
__PIOB->odr = ~(output_en[N_PIOB]);
__PIOC->odr = ~(output_en[N_PIOC]);
__PIOD->odr = ~(output_en[N_PIOD]);
/* set PIO enable */
__PIOA->per = pio_ctrl[N_PIOA];
__PIOB->per = pio_ctrl[N_PIOB];
__PIOC->per = pio_ctrl[N_PIOC];
__PIOD->per = pio_ctrl[N_PIOD];
/* set PIO disable */
__PIOA->pdr = ~(pio_ctrl[N_PIOA]);
__PIOB->pdr = ~(pio_ctrl[N_PIOB]);
__PIOC->pdr = ~(pio_ctrl[N_PIOC]);
__PIOD->pdr = ~(pio_ctrl[N_PIOD]);
/* set pull-up enable */
__PIOA->puer = pull_up[N_PIOA];
__PIOB->puer = pull_up[N_PIOB];
__PIOC->puer = pull_up[N_PIOC];
__PIOD->puer = pull_up[N_PIOD];
/* set pull-up disable */
__PIOA->pudr = ~(pull_up[N_PIOA]);
__PIOB->pudr = ~(pull_up[N_PIOB]);
__PIOC->pudr = ~(pull_up[N_PIOC]);
__PIOD->pudr = ~(pull_up[N_PIOD]);
}
static struct pinmux_driver_api api_funcs = {
.set = pinmux_set,
.get = pinmux_get,
.pullup = pinmux_pullup,
.input = pinmux_input
};
int pinmux_init(struct device *port)
{
port->driver_api = &api_funcs;
__pinmux_defaults();
return DEV_OK;
}
DEVICE_INIT(pmux, PINMUX_NAME, &pinmux_init, NULL, NULL,
PRIMARY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);