u-boot-brain/drivers/gpio/atmel_pio4.c
Simon Glass 41575d8e4c dm: treewide: Rename auto_alloc_size members to be shorter
This construct is quite long-winded. In earlier days it made some sense
since auto-allocation was a strange concept. But with driver model now
used pretty universally, we can shorten this to 'auto'. This reduces
verbosity and makes it easier to read.

Coincidentally it also ensures that every declaration is on one line,
thus making dtoc's job easier.

Signed-off-by: Simon Glass <sjg@chromium.org>
2020-12-13 08:00:25 -07:00

345 lines
7.5 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Atmel PIO4 device driver
*
* Copyright (C) 2015 Atmel Corporation
* Wenyou.Yang <wenyou.yang@atmel.com>
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <fdtdec.h>
#include <malloc.h>
#include <asm/arch/hardware.h>
#include <asm/gpio.h>
#include <linux/bitops.h>
#include <mach/gpio.h>
#include <mach/atmel_pio4.h>
DECLARE_GLOBAL_DATA_PTR;
static struct atmel_pio4_port *atmel_pio4_port_base(u32 port)
{
struct atmel_pio4_port *base = NULL;
switch (port) {
case AT91_PIO_PORTA:
base = (struct atmel_pio4_port *)ATMEL_BASE_PIOA;
break;
case AT91_PIO_PORTB:
base = (struct atmel_pio4_port *)ATMEL_BASE_PIOB;
break;
case AT91_PIO_PORTC:
base = (struct atmel_pio4_port *)ATMEL_BASE_PIOC;
break;
case AT91_PIO_PORTD:
base = (struct atmel_pio4_port *)ATMEL_BASE_PIOD;
break;
default:
printf("Error: Atmel PIO4: Failed to get PIO base of port#%d!\n",
port);
break;
}
return base;
}
static int atmel_pio4_config_io_func(u32 port, u32 pin,
u32 func, u32 config)
{
struct atmel_pio4_port *port_base;
u32 reg, mask;
if (pin >= ATMEL_PIO_NPINS_PER_BANK)
return -EINVAL;
port_base = atmel_pio4_port_base(port);
if (!port_base)
return -EINVAL;
mask = 1 << pin;
reg = func;
reg |= config;
writel(mask, &port_base->mskr);
writel(reg, &port_base->cfgr);
return 0;
}
int atmel_pio4_set_gpio(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_GPIO,
config);
}
int atmel_pio4_set_a_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_A,
config);
}
int atmel_pio4_set_b_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_B,
config);
}
int atmel_pio4_set_c_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_C,
config);
}
int atmel_pio4_set_d_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_D,
config);
}
int atmel_pio4_set_e_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_E,
config);
}
int atmel_pio4_set_f_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_F,
config);
}
int atmel_pio4_set_g_periph(u32 port, u32 pin, u32 config)
{
return atmel_pio4_config_io_func(port, pin,
ATMEL_PIO_CFGR_FUNC_PERIPH_G,
config);
}
int atmel_pio4_set_pio_output(u32 port, u32 pin, u32 value)
{
struct atmel_pio4_port *port_base;
u32 reg, mask;
if (pin >= ATMEL_PIO_NPINS_PER_BANK)
return -EINVAL;
port_base = atmel_pio4_port_base(port);
if (!port_base)
return -EINVAL;
mask = 0x01 << pin;
reg = ATMEL_PIO_CFGR_FUNC_GPIO | ATMEL_PIO_DIR_MASK;
writel(mask, &port_base->mskr);
writel(reg, &port_base->cfgr);
if (value)
writel(mask, &port_base->sodr);
else
writel(mask, &port_base->codr);
return 0;
}
int atmel_pio4_get_pio_input(u32 port, u32 pin)
{
struct atmel_pio4_port *port_base;
u32 reg, mask;
if (pin >= ATMEL_PIO_NPINS_PER_BANK)
return -EINVAL;
port_base = atmel_pio4_port_base(port);
if (!port_base)
return -EINVAL;
mask = 0x01 << pin;
reg = ATMEL_PIO_CFGR_FUNC_GPIO;
writel(mask, &port_base->mskr);
writel(reg, &port_base->cfgr);
return (readl(&port_base->pdsr) & mask) ? 1 : 0;
}
#if CONFIG_IS_ENABLED(DM_GPIO)
struct atmel_pioctrl_data {
u32 nbanks;
};
struct atmel_pio4_platdata {
struct atmel_pio4_port *reg_base;
};
static struct atmel_pio4_port *atmel_pio4_bank_base(struct udevice *dev,
u32 bank)
{
struct atmel_pio4_platdata *plat = dev_get_platdata(dev);
struct atmel_pio4_port *port_base =
(struct atmel_pio4_port *)((u32)plat->reg_base +
ATMEL_PIO_BANK_OFFSET * bank);
return port_base;
}
static int atmel_pio4_direction_input(struct udevice *dev, unsigned offset)
{
u32 bank = ATMEL_PIO_BANK(offset);
u32 line = ATMEL_PIO_LINE(offset);
struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
u32 mask = BIT(line);
writel(mask, &port_base->mskr);
clrbits_le32(&port_base->cfgr,
ATMEL_PIO_CFGR_FUNC_MASK | ATMEL_PIO_DIR_MASK);
return 0;
}
static int atmel_pio4_direction_output(struct udevice *dev,
unsigned offset, int value)
{
u32 bank = ATMEL_PIO_BANK(offset);
u32 line = ATMEL_PIO_LINE(offset);
struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
u32 mask = BIT(line);
writel(mask, &port_base->mskr);
clrsetbits_le32(&port_base->cfgr,
ATMEL_PIO_CFGR_FUNC_MASK, ATMEL_PIO_DIR_MASK);
if (value)
writel(mask, &port_base->sodr);
else
writel(mask, &port_base->codr);
return 0;
}
static int atmel_pio4_get_value(struct udevice *dev, unsigned offset)
{
u32 bank = ATMEL_PIO_BANK(offset);
u32 line = ATMEL_PIO_LINE(offset);
struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
u32 mask = BIT(line);
return (readl(&port_base->pdsr) & mask) ? 1 : 0;
}
static int atmel_pio4_set_value(struct udevice *dev,
unsigned offset, int value)
{
u32 bank = ATMEL_PIO_BANK(offset);
u32 line = ATMEL_PIO_LINE(offset);
struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
u32 mask = BIT(line);
if (value)
writel(mask, &port_base->sodr);
else
writel(mask, &port_base->codr);
return 0;
}
static int atmel_pio4_get_function(struct udevice *dev, unsigned offset)
{
u32 bank = ATMEL_PIO_BANK(offset);
u32 line = ATMEL_PIO_LINE(offset);
struct atmel_pio4_port *port_base = atmel_pio4_bank_base(dev, bank);
u32 mask = BIT(line);
writel(mask, &port_base->mskr);
return (readl(&port_base->cfgr) &
ATMEL_PIO_DIR_MASK) ? GPIOF_OUTPUT : GPIOF_INPUT;
}
static const struct dm_gpio_ops atmel_pio4_ops = {
.direction_input = atmel_pio4_direction_input,
.direction_output = atmel_pio4_direction_output,
.get_value = atmel_pio4_get_value,
.set_value = atmel_pio4_set_value,
.get_function = atmel_pio4_get_function,
};
static int atmel_pio4_bind(struct udevice *dev)
{
return dm_scan_fdt_dev(dev);
}
static int atmel_pio4_probe(struct udevice *dev)
{
struct atmel_pio4_platdata *plat = dev_get_platdata(dev);
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct atmel_pioctrl_data *pioctrl_data;
struct clk clk;
fdt_addr_t addr_base;
u32 nbanks;
int ret;
ret = clk_get_by_index(dev, 0, &clk);
if (ret)
return ret;
ret = clk_enable(&clk);
if (ret)
return ret;
clk_free(&clk);
addr_base = dev_read_addr(dev);
if (addr_base == FDT_ADDR_T_NONE)
return -EINVAL;
plat->reg_base = (struct atmel_pio4_port *)addr_base;
pioctrl_data = (struct atmel_pioctrl_data *)dev_get_driver_data(dev);
nbanks = pioctrl_data->nbanks;
uc_priv->bank_name = fdt_get_name(gd->fdt_blob, dev_of_offset(dev),
NULL);
uc_priv->gpio_count = nbanks * ATMEL_PIO_NPINS_PER_BANK;
return 0;
}
/*
* The number of banks can be different from a SoC to another one.
* We can have up to 16 banks.
*/
static const struct atmel_pioctrl_data atmel_sama5d2_pioctrl_data = {
.nbanks = 4,
};
static const struct udevice_id atmel_pio4_ids[] = {
{
.compatible = "atmel,sama5d2-gpio",
.data = (ulong)&atmel_sama5d2_pioctrl_data,
},
{}
};
U_BOOT_DRIVER(gpio_atmel_pio4) = {
.name = "gpio_atmel_pio4",
.id = UCLASS_GPIO,
.ops = &atmel_pio4_ops,
.probe = atmel_pio4_probe,
.bind = atmel_pio4_bind,
.of_match = atmel_pio4_ids,
.platdata_auto = sizeof(struct atmel_pio4_platdata),
};
#endif