Linux debugging

Check our new training course

Linux debugging, tracing, profiling & perf. analysis

Check our new training course
with Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2016 Nordic Semiconductor ASA
 *
 * 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 Driver for the Nordic Semiconductor nRF5X GPIO module.
 */

#include <errno.h>

#include <nanokernel.h>
#include <device.h>
#include <init.h>
#include <gpio.h>
#include <soc.h>
#include <sys_io.h>

/* GPIO structure for nRF5X. More detailed description of each register can be found in nrf5X.h */
struct _gpio {
	__I  uint32_t RESERVED0[321];
	__IO uint32_t OUT;
	__IO uint32_t OUTSET;
	__IO uint32_t OUTCLR;

	__I uint32_t  IN;
	__IO uint32_t DIR;
	__IO uint32_t DIRSET;
	__IO uint32_t DIRCLR;
	__IO uint32_t LATCH;
	__IO uint32_t DETECTMODE;
	__I uint32_t  RESERVED1[118];
	__IO uint32_t PIN_CNF[32];
};

/* GPIOTE structure for nRF5X. More detailed description of each register can be found in nrf5X.h */
struct _gpiote {
	__O uint32_t  TASKS_OUT[8];
	__I uint32_t  RESERVED0[4];

	__O uint32_t  TASKS_SET[8];
	__I uint32_t  RESERVED1[4];

	__O uint32_t  TASKS_CLR[8];
	__I uint32_t  RESERVED2[32];
	__IO uint32_t EVENTS_IN[8];
	__I uint32_t  RESERVED3[23];
	__IO uint32_t EVENTS_PORT;
	__I uint32_t  RESERVED4[97];
	__IO uint32_t INTENSET;
	__IO uint32_t INTENCLR;
	__I uint32_t  RESERVED5[129];
	__IO uint32_t CONFIG[8];
};

/** Configuration data */
struct gpio_nrf5_config {
	/* GPIO module base address */
	uint32_t gpio_base_addr;
	/* Port Control module base address */
	uint32_t port_base_addr;
	/* GPIO Task Event base address */
	uint32_t gpiote_base_addr;
};

struct gpio_nrf5_data {
	/* port ISR callback routine address */
	gpio_callback_t callback_func;
	/* pin callback routine enable flags, by pin number */
	uint32_t pin_callback_enables;
	/* port callback routine enable flag */
	uint8_t port_callback_enable;
};

/* convenience defines for GPIO */
#define DEV_GPIO_CFG(dev) \
	((struct gpio_nrf5_config * const)(dev)->config->config_info)
#define DEV_GPIO_DATA(dev) \
	((struct gpio_nrf5_dev_data_t * const)(dev)->driver_data)
#define GPIO_STRUCT(dev) \
	((volatile struct _gpio *)(DEV_GPIO_CFG(dev))->gpio_base_addr)

/* convenience defines for GPIOTE */
#define GPIOTE_STRUCT(dev) \
	((volatile struct _gpiote *)(DEV_GPIO_CFG(dev))->gpiote_base_addr)


#define GPIO_SENSE_DISABLE    (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
#define GPIO_SENSE_ENABLE     (GPIO_PIN_CNF_SENSE_Enabled << GPIO_PIN_CNF_SENSE_Pos)
#define GPIO_PULL_DISABLE     (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
#define GPIO_PULL_DOWN        (GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos)
#define GPIO_PULL_UP          (GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
#define GPIO_INPUT_CONNECT    (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
#define GPIO_INPUT_DISCONNECT (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
#define GPIO_DIR_INPUT        (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
#define GPIO_DIR_OUTPUT       (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos)

#define GPIO_DRIVE_S0S1 (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
#define GPIO_DRIVE_H0S1 (GPIO_PIN_CNF_DRIVE_H0S1 << GPIO_PIN_CNF_DRIVE_Pos)
#define GPIO_DRIVE_S0H1 (GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos)
#define GPIO_DRIVE_H0H1 (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos)
#define GPIO_DRIVE_D0S1 (GPIO_PIN_CNF_DRIVE_D0S1 << GPIO_PIN_CNF_DRIVE_Pos)
#define GPIO_DRIVE_D0H1 (GPIO_PIN_CNF_DRIVE_D0H1 << GPIO_PIN_CNF_DRIVE_Pos)
#define GPIO_DRIVE_S0D1 (GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
#define GPIO_DRIVE_H0D1 (GPIO_PIN_CNF_DRIVE_H0D1 << GPIO_PIN_CNF_DRIVE_Pos)

/**
 * @brief Configure pin or port
 */
static int gpio_nrf5_config(struct device *dev,
			    int access_op, uint32_t pin, int flags)
{
	volatile struct _gpio *gpio = GPIO_STRUCT(dev);

	if (access_op == GPIO_ACCESS_BY_PIN) {

		/* Check pull */
		uint8_t pull = GPIO_PULL_DISABLE;

		if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_UP) {
			pull = GPIO_PULL_UP;
		} else if ((flags & GPIO_PUD_MASK) == GPIO_PUD_PULL_DOWN) {
			pull = GPIO_PULL_DOWN;
		}

		if ((flags & GPIO_DIR_MASK) == GPIO_DIR_OUT) {
			/* Config as output */
			gpio->PIN_CNF[pin] = GPIO_SENSE_DISABLE |
					     GPIO_DRIVE_S0S1    |
					     pull               |
					     GPIO_INPUT_CONNECT |
					     GPIO_DIR_OUTPUT;
		} else {
			/* Config as input */
			gpio->PIN_CNF[pin] = GPIO_SENSE_DISABLE |
					     GPIO_DRIVE_S0S1    |
					     pull               |
					     GPIO_INPUT_CONNECT |
					     GPIO_DIR_INPUT;
		}
	}

	return 0;
}

/**
 * @brief Handler for port interrupts
 * @param dev Pointer to device structure for driver instance
 *
 * @return N/A
 */
static void gpio_nrf5_port_isr(void *dev)
{
}

static struct gpio_driver_api gpio_nrf5_drv_api_funcs = {
	.config = gpio_nrf5_config,
};

/* Initialization for GPIO Port 0 */
#ifdef CONFIG_GPIO_NRF5_P0

static int gpio_nrf5_P0_init(struct device *dev);

static struct gpio_nrf5_config gpio_nrf5_P0_cfg = {
	.gpio_base_addr   = NRF_P0_BASE,
	.port_base_addr   = NRF_P0_BASE,
	.gpiote_base_addr = NRF_GPIOTE_BASE,
};

static struct gpio_nrf5_data gpio_data_P0;

DEVICE_AND_API_INIT(gpio_nrf5_P0, CONFIG_GPIO_NRF5_P0_DEV_NAME, gpio_nrf5_P0_init,
		    &gpio_data_P0, &gpio_nrf5_P0_cfg,
		    SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
		    &gpio_nrf5_drv_api_funcs);

static int gpio_nrf5_P0_init(struct device *dev)
{
	IRQ_CONNECT(GPIOTE_IRQn, CONFIG_GPIO_NRF5_PORT_P0_PRI,
		    gpio_nrf5_port_isr, DEVICE_GET(gpio_nrf5_P0), 0);

	irq_enable(GPIOTE_IRQn);

	return 0;
}

#endif /* CONFIG_GPIO_NRF5_P0 */