-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
gpio/mpc83xx_spisel_boot.c: gpio driver for SPISEL_BOOT signal
Some SoCs in the mpc83xx family, e.g. mpc8309, have a dedicated spi chip select, SPISEL_BOOT, that is used by the boot code to boot from flash. This chip select will typically be used to select a SPI boot flash. The SPISEL_BOOT signal is controlled by a single bit in the SPI_CS register. Implement a gpio driver for the spi chip select register. This allows a spi driver capable of using gpios as chip select, to bind a chip select to SPISEL_BOOT. It may be a little odd to do this as a GPIO driver, since the signal is neither GP or I, but it is quite convenient to present it to the spi driver that way. The alternative it to teach mpc8xxx_spi to handle the SPISEL_BOOT signal itself (that is how it's done in the linux kernel, see commit 69b921acae8a) Signed-off-by: Klaus H. Sorensen <[email protected]> Signed-off-by: Rasmus Villemoes <[email protected]>
- Loading branch information
Showing
4 changed files
with
179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
MPC83xx SPISEL_BOOT gpio controller | ||
|
||
Provide access to MPC83xx SPISEL_BOOT signal as a gpio to allow it to be | ||
easily bound as a SPI controller chip select. | ||
|
||
The SPISEL_BOOT signal is always an output. | ||
|
||
Required properties: | ||
|
||
- compatible: must be "fsl,mpc83xx-spisel-boot" or "fsl,mpc8309-spisel-boot". | ||
- reg: must point to the SPI_CS register in the SoC register map. | ||
- ngpios: number of gpios provided by driver, normally 1. | ||
|
||
Example: | ||
|
||
spisel_boot: spisel_boot@14c { | ||
compatible = "fsl,mpc8309-spisel-boot"; | ||
reg = <0x14c 0x04>; | ||
#gpio-cells = <2>; | ||
device_type = "gpio"; | ||
ngpios = <1>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
// SPDX-License-Identifier: GPL-2.0+ | ||
/* | ||
* (C) Copyright 2019 DEIF A/S | ||
* | ||
* GPIO driver to set/clear SPISEL_BOOT pin on mpc83xx. | ||
*/ | ||
|
||
#include <common.h> | ||
#include <dm.h> | ||
#include <mapmem.h> | ||
#include <asm/gpio.h> | ||
|
||
struct mpc83xx_spisel_boot { | ||
u32 __iomem *spi_cs; | ||
ulong addr; | ||
uint gpio_count; | ||
ulong type; | ||
}; | ||
|
||
static u32 gpio_mask(uint gpio) | ||
{ | ||
return (1U << (31 - (gpio))); | ||
} | ||
|
||
static int mpc83xx_spisel_boot_direction_input(struct udevice *dev, uint gpio) | ||
{ | ||
return -EINVAL; | ||
} | ||
|
||
static int mpc83xx_spisel_boot_set_value(struct udevice *dev, uint gpio, int value) | ||
{ | ||
struct mpc83xx_spisel_boot *data = dev_get_priv(dev); | ||
|
||
debug("%s: gpio=%d, value=%u, gpio_mask=0x%08x\n", __func__, | ||
gpio, value, gpio_mask(gpio)); | ||
|
||
if (value) | ||
setbits_be32(data->spi_cs, gpio_mask(gpio)); | ||
else | ||
clrbits_be32(data->spi_cs, gpio_mask(gpio)); | ||
|
||
return 0; | ||
} | ||
|
||
static int mpc83xx_spisel_boot_direction_output(struct udevice *dev, uint gpio, int value) | ||
{ | ||
return 0; | ||
} | ||
|
||
static int mpc83xx_spisel_boot_get_value(struct udevice *dev, uint gpio) | ||
{ | ||
struct mpc83xx_spisel_boot *data = dev_get_priv(dev); | ||
|
||
return !!(in_be32(data->spi_cs) & gpio_mask(gpio)); | ||
} | ||
|
||
static int mpc83xx_spisel_boot_get_function(struct udevice *dev, uint gpio) | ||
{ | ||
return GPIOF_OUTPUT; | ||
} | ||
|
||
#if CONFIG_IS_ENABLED(OF_CONTROL) | ||
static int mpc83xx_spisel_boot_ofdata_to_platdata(struct udevice *dev) | ||
{ | ||
struct mpc8xxx_gpio_plat *plat = dev_get_platdata(dev); | ||
fdt_addr_t addr; | ||
u32 reg[2]; | ||
|
||
dev_read_u32_array(dev, "reg", reg, 2); | ||
addr = dev_translate_address(dev, reg); | ||
|
||
plat->addr = addr; | ||
plat->size = reg[1]; | ||
plat->ngpios = dev_read_u32_default(dev, "ngpios", 1); | ||
|
||
return 0; | ||
} | ||
#endif | ||
|
||
static int mpc83xx_spisel_boot_platdata_to_priv(struct udevice *dev) | ||
{ | ||
struct mpc83xx_spisel_boot *priv = dev_get_priv(dev); | ||
struct mpc8xxx_gpio_plat *plat = dev_get_platdata(dev); | ||
unsigned long size = plat->size; | ||
ulong driver_data = dev_get_driver_data(dev); | ||
|
||
if (size == 0) | ||
size = 0x04; | ||
|
||
priv->addr = plat->addr; | ||
priv->spi_cs = map_sysmem(plat->addr, size); | ||
|
||
if (!priv->spi_cs) | ||
return -ENOMEM; | ||
|
||
priv->gpio_count = plat->ngpios; | ||
|
||
priv->type = driver_data; | ||
|
||
return 0; | ||
} | ||
|
||
static int mpc83xx_spisel_boot_probe(struct udevice *dev) | ||
{ | ||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); | ||
struct mpc83xx_spisel_boot *data = dev_get_priv(dev); | ||
char name[32], *str; | ||
|
||
mpc83xx_spisel_boot_platdata_to_priv(dev); | ||
|
||
snprintf(name, sizeof(name), "MPC@%lx_", data->addr); | ||
str = strdup(name); | ||
|
||
if (!str) | ||
return -ENOMEM; | ||
|
||
uc_priv->bank_name = str; | ||
uc_priv->gpio_count = data->gpio_count; | ||
|
||
return 0; | ||
} | ||
|
||
static const struct dm_gpio_ops mpc83xx_spisel_boot_ops = { | ||
.direction_input = mpc83xx_spisel_boot_direction_input, | ||
.direction_output = mpc83xx_spisel_boot_direction_output, | ||
.get_value = mpc83xx_spisel_boot_get_value, | ||
.set_value = mpc83xx_spisel_boot_set_value, | ||
.get_function = mpc83xx_spisel_boot_get_function, | ||
}; | ||
|
||
static const struct udevice_id mpc83xx_spisel_boot_ids[] = { | ||
{ .compatible = "fsl,mpc8309-spisel-boot" }, | ||
{ .compatible = "fsl,mpc83xx-spisel-boot" }, | ||
{ /* sentinel */ } | ||
}; | ||
|
||
U_BOOT_DRIVER(spisel_boot_mpc83xx) = { | ||
.name = "spisel_boot_mpc83xx", | ||
.id = UCLASS_GPIO, | ||
.ops = &mpc83xx_spisel_boot_ops, | ||
#if CONFIG_IS_ENABLED(OF_CONTROL) | ||
.ofdata_to_platdata = mpc83xx_spisel_boot_ofdata_to_platdata, | ||
.platdata_auto_alloc_size = sizeof(struct mpc8xxx_gpio_plat), | ||
.of_match = mpc83xx_spisel_boot_ids, | ||
#endif | ||
.probe = mpc83xx_spisel_boot_probe, | ||
.priv_auto_alloc_size = sizeof(struct mpc83xx_spisel_boot), | ||
}; |