Merge branch 'master' of git://git.denx.de/u-boot-atmel
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
config CLK_AT91
|
||||
bool "AT91 clock drivers"
|
||||
depends on CLK
|
||||
select MISC
|
||||
help
|
||||
This option is used to enable the AT91 clock driver.
|
||||
The driver supports the AT91 clock generator, including
|
||||
|
||||
@@ -17,15 +17,41 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
#define GENERATED_SOURCE_MAX 6
|
||||
#define GENERATED_MAX_DIV 255
|
||||
|
||||
struct generated_clk_priv {
|
||||
/**
|
||||
* generated_clk_bind() - for the generated clock driver
|
||||
* Recursively bind its children as clk devices.
|
||||
*
|
||||
* @return: 0 on success, or negative error code on failure
|
||||
*/
|
||||
static int generated_clk_bind(struct udevice *dev)
|
||||
{
|
||||
return at91_clk_sub_device_bind(dev, "generic-clk");
|
||||
}
|
||||
|
||||
static const struct udevice_id generated_clk_match[] = {
|
||||
{ .compatible = "atmel,sama5d2-clk-generated" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(generated_clk) = {
|
||||
.name = "generated-clk",
|
||||
.id = UCLASS_MISC,
|
||||
.of_match = generated_clk_match,
|
||||
.bind = generated_clk_bind,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
struct generic_clk_priv {
|
||||
u32 num_parents;
|
||||
};
|
||||
|
||||
static ulong generated_clk_get_rate(struct clk *clk)
|
||||
static ulong generic_clk_get_rate(struct clk *clk)
|
||||
{
|
||||
struct pmc_platdata *plat = dev_get_platdata(clk->dev);
|
||||
struct at91_pmc *pmc = plat->reg_base;
|
||||
struct clk parent;
|
||||
ulong clk_rate;
|
||||
u32 tmp, gckdiv;
|
||||
u8 parent_id;
|
||||
int ret;
|
||||
@@ -36,18 +62,22 @@ static ulong generated_clk_get_rate(struct clk *clk)
|
||||
AT91_PMC_PCR_GCKCSS_MASK;
|
||||
gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK;
|
||||
|
||||
ret = clk_get_by_index(clk->dev, parent_id, &parent);
|
||||
ret = clk_get_by_index(dev_get_parent(clk->dev), parent_id, &parent);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
return clk_get_rate(&parent) / (gckdiv + 1);
|
||||
clk_rate = clk_get_rate(&parent) / (gckdiv + 1);
|
||||
|
||||
clk_free(&parent);
|
||||
|
||||
return clk_rate;
|
||||
}
|
||||
|
||||
static ulong generated_clk_set_rate(struct clk *clk, ulong rate)
|
||||
static ulong generic_clk_set_rate(struct clk *clk, ulong rate)
|
||||
{
|
||||
struct pmc_platdata *plat = dev_get_platdata(clk->dev);
|
||||
struct at91_pmc *pmc = plat->reg_base;
|
||||
struct generated_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
struct generic_clk_priv *priv = dev_get_priv(clk->dev);
|
||||
struct clk parent, best_parent;
|
||||
ulong tmp_rate, best_rate = rate, parent_rate;
|
||||
int tmp_diff, best_diff = -1;
|
||||
@@ -58,7 +88,7 @@ static ulong generated_clk_set_rate(struct clk *clk, ulong rate)
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < priv->num_parents; i++) {
|
||||
ret = clk_get_by_index(clk->dev, i, &parent);
|
||||
ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -111,18 +141,20 @@ static ulong generated_clk_set_rate(struct clk *clk, ulong rate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops generated_clk_ops = {
|
||||
.get_rate = generated_clk_get_rate,
|
||||
.set_rate = generated_clk_set_rate,
|
||||
static struct clk_ops generic_clk_ops = {
|
||||
.of_xlate = at91_clk_of_xlate,
|
||||
.get_rate = generic_clk_get_rate,
|
||||
.set_rate = generic_clk_set_rate,
|
||||
};
|
||||
|
||||
static int generated_clk_ofdata_to_platdata(struct udevice *dev)
|
||||
static int generic_clk_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct generated_clk_priv *priv = dev_get_priv(dev);
|
||||
struct generic_clk_priv *priv = dev_get_priv(dev);
|
||||
u32 cells[GENERATED_SOURCE_MAX];
|
||||
u32 num_parents;
|
||||
|
||||
num_parents = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset,
|
||||
num_parents = fdtdec_get_int_array_count(gd->fdt_blob,
|
||||
dev_get_parent(dev)->of_offset,
|
||||
"clocks", cells,
|
||||
GENERATED_SOURCE_MAX);
|
||||
|
||||
@@ -134,29 +166,12 @@ static int generated_clk_ofdata_to_platdata(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generated_clk_bind(struct udevice *dev)
|
||||
{
|
||||
return at91_pmc_clk_node_bind(dev);
|
||||
}
|
||||
|
||||
static int generated_clk_probe(struct udevice *dev)
|
||||
{
|
||||
return at91_pmc_core_probe(dev);
|
||||
}
|
||||
|
||||
static const struct udevice_id generated_clk_match[] = {
|
||||
{ .compatible = "atmel,sama5d2-clk-generated" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(generated_clk) = {
|
||||
.name = "generated-clk",
|
||||
U_BOOT_DRIVER(generic_clk) = {
|
||||
.name = "generic-clk",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = generated_clk_match,
|
||||
.bind = generated_clk_bind,
|
||||
.probe = generated_clk_probe,
|
||||
.ofdata_to_platdata = generated_clk_ofdata_to_platdata,
|
||||
.priv_auto_alloc_size = sizeof(struct generated_clk_priv),
|
||||
.probe = at91_clk_probe,
|
||||
.ofdata_to_platdata = generic_clk_ofdata_to_platdata,
|
||||
.priv_auto_alloc_size = sizeof(struct generic_clk_priv),
|
||||
.platdata_auto_alloc_size = sizeof(struct pmc_platdata),
|
||||
.ops = &generated_clk_ops,
|
||||
.ops = &generic_clk_ops,
|
||||
};
|
||||
|
||||
@@ -16,7 +16,32 @@
|
||||
#define PERIPHERAL_ID_MAX 31
|
||||
#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
|
||||
|
||||
static int sam9x5_periph_clk_enable(struct clk *clk)
|
||||
/**
|
||||
* sam9x5_periph_clk_bind() - for the periph clock driver
|
||||
* Recursively bind its children as clk devices.
|
||||
*
|
||||
* @return: 0 on success, or negative error code on failure
|
||||
*/
|
||||
static int sam9x5_periph_clk_bind(struct udevice *dev)
|
||||
{
|
||||
return at91_clk_sub_device_bind(dev, "periph-clk");
|
||||
}
|
||||
|
||||
static const struct udevice_id sam9x5_periph_clk_match[] = {
|
||||
{ .compatible = "atmel,at91sam9x5-clk-peripheral" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(sam9x5_periph_clk) = {
|
||||
.name = "sam9x5-periph-clk",
|
||||
.id = UCLASS_MISC,
|
||||
.of_match = sam9x5_periph_clk_match,
|
||||
.bind = sam9x5_periph_clk_bind,
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------*/
|
||||
|
||||
static int periph_clk_enable(struct clk *clk)
|
||||
{
|
||||
struct pmc_platdata *plat = dev_get_platdata(clk->dev);
|
||||
struct at91_pmc *pmc = plat->reg_base;
|
||||
@@ -30,31 +55,36 @@ static int sam9x5_periph_clk_enable(struct clk *clk)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops sam9x5_periph_clk_ops = {
|
||||
.enable = sam9x5_periph_clk_enable,
|
||||
};
|
||||
|
||||
static int sam9x5_periph_clk_bind(struct udevice *dev)
|
||||
static ulong periph_get_rate(struct clk *clk)
|
||||
{
|
||||
return at91_pmc_clk_node_bind(dev);
|
||||
struct udevice *dev;
|
||||
struct clk clk_dev;
|
||||
ulong clk_rate;
|
||||
int ret;
|
||||
|
||||
dev = dev_get_parent(clk->dev);
|
||||
|
||||
ret = clk_get_by_index(dev, 0, &clk_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_rate = clk_get_rate(&clk_dev);
|
||||
|
||||
clk_free(&clk_dev);
|
||||
|
||||
return clk_rate;
|
||||
}
|
||||
|
||||
static int sam9x5_periph_clk_probe(struct udevice *dev)
|
||||
{
|
||||
return at91_pmc_core_probe(dev);
|
||||
}
|
||||
|
||||
static const struct udevice_id sam9x5_periph_clk_match[] = {
|
||||
{ .compatible = "atmel,at91sam9x5-clk-peripheral" },
|
||||
{}
|
||||
static struct clk_ops periph_clk_ops = {
|
||||
.of_xlate = at91_clk_of_xlate,
|
||||
.enable = periph_clk_enable,
|
||||
.get_rate = periph_get_rate,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(sam9x5_periph_clk) = {
|
||||
.name = "sam9x5-periph-clk",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = sam9x5_periph_clk_match,
|
||||
.bind = sam9x5_periph_clk_bind,
|
||||
.probe = sam9x5_periph_clk_probe,
|
||||
U_BOOT_DRIVER(clk_periph) = {
|
||||
.name = "periph-clk",
|
||||
.id = UCLASS_CLK,
|
||||
.platdata_auto_alloc_size = sizeof(struct pmc_platdata),
|
||||
.ops = &sam9x5_periph_clk_ops,
|
||||
.probe = at91_clk_probe,
|
||||
.ops = &periph_clk_ops,
|
||||
};
|
||||
|
||||
@@ -14,12 +14,37 @@
|
||||
|
||||
#define SYSTEM_MAX_ID 31
|
||||
|
||||
/**
|
||||
* at91_system_clk_bind() - for the system clock driver
|
||||
* Recursively bind its children as clk devices.
|
||||
*
|
||||
* @return: 0 on success, or negative error code on failure
|
||||
*/
|
||||
static int at91_system_clk_bind(struct udevice *dev)
|
||||
{
|
||||
return at91_clk_sub_device_bind(dev, "system-clk");
|
||||
}
|
||||
|
||||
static const struct udevice_id at91_system_clk_match[] = {
|
||||
{ .compatible = "atmel,at91rm9200-clk-system" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(at91_system_clk) = {
|
||||
.name = "at91-system-clk",
|
||||
.id = UCLASS_MISC,
|
||||
.of_match = at91_system_clk_match,
|
||||
.bind = at91_system_clk_bind,
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
static inline int is_pck(int id)
|
||||
{
|
||||
return (id >= 8) && (id <= 15);
|
||||
}
|
||||
|
||||
static int at91_system_clk_enable(struct clk *clk)
|
||||
static int system_clk_enable(struct clk *clk)
|
||||
{
|
||||
struct pmc_platdata *plat = dev_get_platdata(clk->dev);
|
||||
struct at91_pmc *pmc = plat->reg_base;
|
||||
@@ -46,31 +71,15 @@ static int at91_system_clk_enable(struct clk *clk)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops at91_system_clk_ops = {
|
||||
.enable = at91_system_clk_enable,
|
||||
static struct clk_ops system_clk_ops = {
|
||||
.of_xlate = at91_clk_of_xlate,
|
||||
.enable = system_clk_enable,
|
||||
};
|
||||
|
||||
static int at91_system_clk_bind(struct udevice *dev)
|
||||
{
|
||||
return at91_pmc_clk_node_bind(dev);
|
||||
}
|
||||
|
||||
static int at91_system_clk_probe(struct udevice *dev)
|
||||
{
|
||||
return at91_pmc_core_probe(dev);
|
||||
}
|
||||
|
||||
static const struct udevice_id at91_system_clk_match[] = {
|
||||
{ .compatible = "atmel,at91rm9200-clk-system" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(at91_system_clk) = {
|
||||
.name = "at91-system-clk",
|
||||
U_BOOT_DRIVER(system_clk) = {
|
||||
.name = "system-clk",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = at91_system_clk_match,
|
||||
.bind = at91_system_clk_bind,
|
||||
.probe = at91_system_clk_probe,
|
||||
.probe = at91_clk_probe,
|
||||
.platdata_auto_alloc_size = sizeof(struct pmc_platdata),
|
||||
.ops = &at91_system_clk_ops,
|
||||
.ops = &system_clk_ops,
|
||||
};
|
||||
|
||||
@@ -14,23 +14,19 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static int at91_pmc_bind(struct udevice *dev)
|
||||
{
|
||||
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
|
||||
}
|
||||
|
||||
static const struct udevice_id at91_pmc_match[] = {
|
||||
{ .compatible = "atmel,sama5d2-pmc" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(at91_pmc) = {
|
||||
.name = "at91-pmc-core",
|
||||
.id = UCLASS_CLK,
|
||||
.name = "at91-pmc",
|
||||
.id = UCLASS_SIMPLE_BUS,
|
||||
.of_match = at91_pmc_match,
|
||||
.bind = at91_pmc_bind,
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------*/
|
||||
|
||||
int at91_pmc_core_probe(struct udevice *dev)
|
||||
{
|
||||
struct pmc_platdata *plat = dev_get_platdata(dev);
|
||||
@@ -42,21 +38,41 @@ int at91_pmc_core_probe(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at91_pmc_clk_node_bind(struct udevice *dev)
|
||||
/**
|
||||
* at91_clk_sub_device_bind() - for the at91 clock driver
|
||||
* Recursively bind its children as clk devices.
|
||||
*
|
||||
* @return: 0 on success, or negative error code on failure
|
||||
*/
|
||||
int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name)
|
||||
{
|
||||
const void *fdt = gd->fdt_blob;
|
||||
int offset = dev->of_offset;
|
||||
bool pre_reloc_only = !(gd->flags & GD_FLG_RELOC);
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
for (offset = fdt_first_subnode(fdt, offset);
|
||||
offset > 0;
|
||||
offset = fdt_next_subnode(fdt, offset)) {
|
||||
if (pre_reloc_only &&
|
||||
!fdt_getprop(fdt, offset, "u-boot,dm-pre-reloc", NULL))
|
||||
continue;
|
||||
/*
|
||||
* If this node has "compatible" property, this is not
|
||||
* a clock sub-node, but a normal device. skip.
|
||||
*/
|
||||
fdt_get_property(fdt, offset, "compatible", &ret);
|
||||
if (ret >= 0)
|
||||
continue;
|
||||
|
||||
if (ret != -FDT_ERR_NOTFOUND)
|
||||
return ret;
|
||||
|
||||
name = fdt_get_name(fdt, offset, NULL);
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
|
||||
ret = device_bind_driver_to_node(dev, "clk", name,
|
||||
ret = device_bind_driver_to_node(dev, drv_name, name,
|
||||
offset, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -65,7 +81,33 @@ int at91_pmc_clk_node_bind(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(clk_generic) = {
|
||||
.id = UCLASS_CLK,
|
||||
.name = "clk",
|
||||
};
|
||||
int at91_clk_of_xlate(struct clk *clk, struct fdtdec_phandle_args *args)
|
||||
{
|
||||
int periph;
|
||||
|
||||
if (args->args_count) {
|
||||
debug("Invalid args_count: %d\n", args->args_count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
periph = fdtdec_get_uint(gd->fdt_blob, clk->dev->of_offset, "reg", -1);
|
||||
if (periph < 0)
|
||||
return -EINVAL;
|
||||
|
||||
clk->id = periph;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at91_clk_probe(struct udevice *dev)
|
||||
{
|
||||
struct udevice *dev_periph_container, *dev_pmc;
|
||||
struct pmc_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
dev_periph_container = dev_get_parent(dev);
|
||||
dev_pmc = dev_get_parent(dev_periph_container);
|
||||
|
||||
plat->reg_base = (struct at91_pmc *)dev_get_addr_ptr(dev_pmc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ struct pmc_platdata {
|
||||
};
|
||||
|
||||
int at91_pmc_core_probe(struct udevice *dev);
|
||||
int at91_pmc_clk_node_bind(struct udevice *dev);
|
||||
int at91_clk_sub_device_bind(struct udevice *dev, const char *drv_name);
|
||||
|
||||
int at91_clk_of_xlate(struct clk *clk, struct fdtdec_phandle_args *args);
|
||||
int at91_clk_probe(struct udevice *dev);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,25 +6,18 @@
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/root.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static int at91_sckc_clk_bind(struct udevice *dev)
|
||||
{
|
||||
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
|
||||
}
|
||||
|
||||
static const struct udevice_id at91_sckc_clk_match[] = {
|
||||
static const struct udevice_id at91_sckc_match[] = {
|
||||
{ .compatible = "atmel,at91sam9x5-sckc" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(at91_sckc_clk) = {
|
||||
.name = "at91_sckc_clk",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = at91_sckc_clk_match,
|
||||
.bind = at91_sckc_clk_bind,
|
||||
U_BOOT_DRIVER(at91_sckc) = {
|
||||
.name = "at91-sckc",
|
||||
.id = UCLASS_SIMPLE_BUS,
|
||||
.of_match = at91_sckc_match,
|
||||
};
|
||||
|
||||
@@ -80,6 +80,9 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk->dev = dev_clk;
|
||||
|
||||
ops = clk_dev_ops(dev_clk);
|
||||
|
||||
if (ops->of_xlate)
|
||||
|
||||
@@ -284,27 +284,15 @@ 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 udevice *dev_clk;
|
||||
struct clk clk;
|
||||
fdt_addr_t addr_base;
|
||||
u32 nbanks;
|
||||
int periph;
|
||||
int ret;
|
||||
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
periph = fdtdec_get_uint(gd->fdt_blob, clk.dev->of_offset, "reg", -1);
|
||||
if (periph < 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev_clk = dev_get_parent(clk.dev);
|
||||
ret = clk_request(dev_clk, &clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk.id = periph;
|
||||
ret = clk_enable(&clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -176,37 +176,21 @@ static void at91_calc_i2c_clock(struct udevice *dev, int i2c_clk)
|
||||
static int at91_i2c_enable_clk(struct udevice *dev)
|
||||
{
|
||||
struct at91_i2c_bus *bus = dev_get_priv(dev);
|
||||
struct udevice *dev_clk;
|
||||
struct clk clk;
|
||||
ulong clk_rate;
|
||||
int periph;
|
||||
int ret;
|
||||
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
periph = fdtdec_get_uint(gd->fdt_blob, clk.dev->of_offset, "reg", -1);
|
||||
if (periph < 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev_clk = dev_get_parent(clk.dev);
|
||||
ret = clk_request(dev_clk, &clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk.id = periph;
|
||||
ret = clk_enable(&clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_get_by_index(dev_clk, 0, &clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_rate = clk_get_rate(&clk);
|
||||
if (!clk_rate)
|
||||
return -ENODEV;
|
||||
return -EINVAL;
|
||||
|
||||
bus->bus_clk_rate = clk_rate;
|
||||
|
||||
|
||||
@@ -50,29 +50,6 @@ struct atmel_sdhci_plat {
|
||||
struct mmc mmc;
|
||||
};
|
||||
|
||||
static int atmel_sdhci_get_clk(struct udevice *dev, int index, struct clk *clk)
|
||||
{
|
||||
struct udevice *dev_clk;
|
||||
int periph, ret;
|
||||
|
||||
ret = clk_get_by_index(dev, index, clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
periph = fdtdec_get_uint(gd->fdt_blob, clk->dev->of_offset, "reg", -1);
|
||||
if (periph < 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev_clk = dev_get_parent(clk->dev);
|
||||
ret = clk_request(dev_clk, clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk->id = periph;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_sdhci_probe(struct udevice *dev)
|
||||
{
|
||||
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
|
||||
@@ -85,7 +62,7 @@ static int atmel_sdhci_probe(struct udevice *dev)
|
||||
struct clk clk;
|
||||
int ret;
|
||||
|
||||
ret = atmel_sdhci_get_clk(dev, 0, &clk);
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -106,7 +83,7 @@ static int atmel_sdhci_probe(struct udevice *dev)
|
||||
clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT;
|
||||
gck_rate = clk_base * 1000000 * (clk_mul + 1);
|
||||
|
||||
ret = atmel_sdhci_get_clk(dev, 1, &clk);
|
||||
ret = clk_get_by_index(dev, 1, &clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -98,6 +98,13 @@ config DEBUG_UART_AR933X
|
||||
driver will be available until the real driver model serial is
|
||||
running.
|
||||
|
||||
config DEBUG_UART_ATMEL
|
||||
bool "Atmel USART"
|
||||
help
|
||||
Select this to enable a debug UART using the atmel usart driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver-model serial is running.
|
||||
|
||||
config DEBUG_UART_NS16550
|
||||
bool "ns16550"
|
||||
help
|
||||
@@ -296,6 +303,13 @@ config AR933X_UART
|
||||
tree binding to operate, please refer to the document at
|
||||
doc/device-tree-bindings/serial/qca,ar9330-uart.txt.
|
||||
|
||||
config ATMEL_USART
|
||||
bool "Atmel USART support"
|
||||
help
|
||||
Select this to enable USART support for Atmel SoCs. It can be
|
||||
configured in the device tree, and input clock frequency can
|
||||
be got from the clk node.
|
||||
|
||||
config FSL_LPUART
|
||||
bool "Freescale LPUART support"
|
||||
help
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <errno.h>
|
||||
#include <watchdog.h>
|
||||
#include <serial.h>
|
||||
#include <debug_uart.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
@@ -226,3 +227,24 @@ U_BOOT_DRIVER(serial_atmel) = {
|
||||
.priv_auto_alloc_size = sizeof(struct atmel_serial_priv),
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_ATMEL
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
atmel_serial_setbrg_internal(usart, 0, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (!(readl(&usart->csr) & USART3_BIT(TXRDY)))
|
||||
;
|
||||
|
||||
writel(ch, &usart->thr);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
||||
|
||||
@@ -32,6 +32,14 @@ config ATH79_SPI
|
||||
uses driver model and requires a device tree binding to operate.
|
||||
please refer to doc/device-tree-bindings/spi/spi-ath79.txt.
|
||||
|
||||
config ATMEL_SPI
|
||||
bool "Atmel SPI driver"
|
||||
depends on ARCH_AT91
|
||||
help
|
||||
This enables driver for the Atmel SPI Controller, present on
|
||||
many AT32 (AVR32) and AT91 (ARM) chips. This driver can be
|
||||
used to access the SPI Flash, such as AT25DF321.
|
||||
|
||||
config CADENCE_QSPI
|
||||
bool "Cadence QSPI driver"
|
||||
help
|
||||
|
||||
@@ -4,16 +4,30 @@
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <spi.h>
|
||||
#include <malloc.h>
|
||||
#include <wait_bit.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#ifdef CONFIG_DM_SPI
|
||||
#include <asm/arch/at91_spi.h>
|
||||
#endif
|
||||
#ifdef CONFIG_DM_GPIO
|
||||
#include <asm/gpio.h>
|
||||
#endif
|
||||
|
||||
#include "atmel_spi.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifndef CONFIG_DM_SPI
|
||||
|
||||
static int spi_has_wdrbt(struct atmel_spi_slave *slave)
|
||||
{
|
||||
unsigned int ver;
|
||||
@@ -209,3 +223,277 @@ out:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define MAX_CS_COUNT 4
|
||||
|
||||
struct atmel_spi_platdata {
|
||||
struct at91_spi *regs;
|
||||
};
|
||||
|
||||
struct atmel_spi_priv {
|
||||
unsigned int freq; /* Default frequency */
|
||||
unsigned int mode;
|
||||
ulong bus_clk_rate;
|
||||
struct gpio_desc cs_gpios[MAX_CS_COUNT];
|
||||
};
|
||||
|
||||
static int atmel_spi_claim_bus(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus);
|
||||
struct atmel_spi_priv *priv = dev_get_priv(bus);
|
||||
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
|
||||
struct at91_spi *reg_base = bus_plat->regs;
|
||||
u32 cs = slave_plat->cs;
|
||||
u32 freq = priv->freq;
|
||||
u32 scbr, csrx, mode;
|
||||
|
||||
scbr = (priv->bus_clk_rate + freq - 1) / freq;
|
||||
if (scbr > ATMEL_SPI_CSRx_SCBR_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (scbr < 1)
|
||||
scbr = 1;
|
||||
|
||||
csrx = ATMEL_SPI_CSRx_SCBR(scbr);
|
||||
csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8);
|
||||
|
||||
if (!(priv->mode & SPI_CPHA))
|
||||
csrx |= ATMEL_SPI_CSRx_NCPHA;
|
||||
if (priv->mode & SPI_CPOL)
|
||||
csrx |= ATMEL_SPI_CSRx_CPOL;
|
||||
|
||||
writel(csrx, ®_base->csr[cs]);
|
||||
|
||||
mode = ATMEL_SPI_MR_MSTR |
|
||||
ATMEL_SPI_MR_MODFDIS |
|
||||
ATMEL_SPI_MR_WDRBT |
|
||||
ATMEL_SPI_MR_PCS(~(1 << cs));
|
||||
|
||||
writel(mode, ®_base->mr);
|
||||
|
||||
writel(ATMEL_SPI_CR_SPIEN, ®_base->cr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_spi_release_bus(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus);
|
||||
|
||||
writel(ATMEL_SPI_CR_SPIDIS, &bus_plat->regs->cr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_spi_cs_activate(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct atmel_spi_priv *priv = dev_get_priv(bus);
|
||||
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
|
||||
u32 cs = slave_plat->cs;
|
||||
|
||||
dm_gpio_set_value(&priv->cs_gpios[cs], 0);
|
||||
}
|
||||
|
||||
static void atmel_spi_cs_deactivate(struct udevice *dev)
|
||||
{
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct atmel_spi_priv *priv = dev_get_priv(bus);
|
||||
struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);
|
||||
u32 cs = slave_plat->cs;
|
||||
|
||||
dm_gpio_set_value(&priv->cs_gpios[cs], 1);
|
||||
}
|
||||
|
||||
static int atmel_spi_xfer(struct udevice *dev, unsigned int bitlen,
|
||||
const void *dout, void *din, unsigned long flags)
|
||||
{
|
||||
struct udevice *bus = dev_get_parent(dev);
|
||||
struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus);
|
||||
struct at91_spi *reg_base = bus_plat->regs;
|
||||
|
||||
u32 len_tx, len_rx, len;
|
||||
u32 status;
|
||||
const u8 *txp = dout;
|
||||
u8 *rxp = din;
|
||||
u8 value;
|
||||
|
||||
if (bitlen == 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* The controller can do non-multiple-of-8 bit
|
||||
* transfers, but this driver currently doesn't support it.
|
||||
*
|
||||
* It's also not clear how such transfers are supposed to be
|
||||
* represented as a stream of bytes...this is a limitation of
|
||||
* the current SPI interface.
|
||||
*/
|
||||
if (bitlen % 8) {
|
||||
/* Errors always terminate an ongoing transfer */
|
||||
flags |= SPI_XFER_END;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = bitlen / 8;
|
||||
|
||||
/*
|
||||
* The controller can do automatic CS control, but it is
|
||||
* somewhat quirky, and it doesn't really buy us much anyway
|
||||
* in the context of U-Boot.
|
||||
*/
|
||||
if (flags & SPI_XFER_BEGIN) {
|
||||
atmel_spi_cs_activate(dev);
|
||||
|
||||
/*
|
||||
* sometimes the RDR is not empty when we get here,
|
||||
* in theory that should not happen, but it DOES happen.
|
||||
* Read it here to be on the safe side.
|
||||
* That also clears the OVRES flag. Required if the
|
||||
* following loop exits due to OVRES!
|
||||
*/
|
||||
readl(®_base->rdr);
|
||||
}
|
||||
|
||||
for (len_tx = 0, len_rx = 0; len_rx < len; ) {
|
||||
status = readl(®_base->sr);
|
||||
|
||||
if (status & ATMEL_SPI_SR_OVRES)
|
||||
return -1;
|
||||
|
||||
if ((len_tx < len) && (status & ATMEL_SPI_SR_TDRE)) {
|
||||
if (txp)
|
||||
value = *txp++;
|
||||
else
|
||||
value = 0;
|
||||
writel(value, ®_base->tdr);
|
||||
len_tx++;
|
||||
}
|
||||
|
||||
if (status & ATMEL_SPI_SR_RDRF) {
|
||||
value = readl(®_base->rdr);
|
||||
if (rxp)
|
||||
*rxp++ = value;
|
||||
len_rx++;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (flags & SPI_XFER_END) {
|
||||
/*
|
||||
* Wait until the transfer is completely done before
|
||||
* we deactivate CS.
|
||||
*/
|
||||
wait_for_bit(__func__, ®_base->sr,
|
||||
ATMEL_SPI_SR_TXEMPTY, true, 1000, false);
|
||||
|
||||
atmel_spi_cs_deactivate(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_spi_set_speed(struct udevice *bus, uint speed)
|
||||
{
|
||||
struct atmel_spi_priv *priv = dev_get_priv(bus);
|
||||
|
||||
priv->freq = speed;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_spi_set_mode(struct udevice *bus, uint mode)
|
||||
{
|
||||
struct atmel_spi_priv *priv = dev_get_priv(bus);
|
||||
|
||||
priv->mode = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_spi_ops atmel_spi_ops = {
|
||||
.claim_bus = atmel_spi_claim_bus,
|
||||
.release_bus = atmel_spi_release_bus,
|
||||
.xfer = atmel_spi_xfer,
|
||||
.set_speed = atmel_spi_set_speed,
|
||||
.set_mode = atmel_spi_set_mode,
|
||||
/*
|
||||
* cs_info is not needed, since we require all chip selects to be
|
||||
* in the device tree explicitly
|
||||
*/
|
||||
};
|
||||
|
||||
static int atmel_spi_enable_clk(struct udevice *bus)
|
||||
{
|
||||
struct atmel_spi_priv *priv = dev_get_priv(bus);
|
||||
struct clk clk;
|
||||
ulong clk_rate;
|
||||
int ret;
|
||||
|
||||
ret = clk_get_by_index(bus, 0, &clk);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
ret = clk_enable(&clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_rate = clk_get_rate(&clk);
|
||||
if (!clk_rate)
|
||||
return -EINVAL;
|
||||
|
||||
priv->bus_clk_rate = clk_rate;
|
||||
|
||||
clk_free(&clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_spi_probe(struct udevice *bus)
|
||||
{
|
||||
struct atmel_spi_platdata *bus_plat = dev_get_platdata(bus);
|
||||
struct atmel_spi_priv *priv = dev_get_priv(bus);
|
||||
int i, ret;
|
||||
|
||||
ret = atmel_spi_enable_clk(bus);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bus_plat->regs = (struct at91_spi *)dev_get_addr(bus);
|
||||
|
||||
ret = gpio_request_list_by_name(bus, "cs-gpios", priv->cs_gpios,
|
||||
ARRAY_SIZE(priv->cs_gpios), 0);
|
||||
if (ret < 0) {
|
||||
error("Can't get %s gpios! Error: %d", bus->name, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) {
|
||||
dm_gpio_set_dir_flags(&priv->cs_gpios[i],
|
||||
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
|
||||
}
|
||||
|
||||
writel(ATMEL_SPI_CR_SWRST, &bus_plat->regs->cr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id atmel_spi_ids[] = {
|
||||
{ .compatible = "atmel,at91rm9200-spi" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(atmel_spi) = {
|
||||
.name = "atmel_spi",
|
||||
.id = UCLASS_SPI,
|
||||
.of_match = atmel_spi_ids,
|
||||
.ops = &atmel_spi_ops,
|
||||
.platdata_auto_alloc_size = sizeof(struct atmel_spi_platdata),
|
||||
.priv_auto_alloc_size = sizeof(struct atmel_spi_priv),
|
||||
.probe = atmel_spi_probe,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -56,9 +56,7 @@ struct ehci_atmel_priv {
|
||||
|
||||
static int ehci_atmel_enable_clk(struct udevice *dev)
|
||||
{
|
||||
struct udevice *dev_clk;
|
||||
struct clk clk;
|
||||
int periph;
|
||||
int ret;
|
||||
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
@@ -73,19 +71,6 @@ static int ehci_atmel_enable_clk(struct udevice *dev)
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
periph = fdtdec_get_uint(gd->fdt_blob, clk.dev->of_offset, "reg", -1);
|
||||
if (periph < 0)
|
||||
return -EINVAL;
|
||||
|
||||
dev_clk = dev_get_parent(clk.dev);
|
||||
if (!dev_clk)
|
||||
return -ENODEV;
|
||||
|
||||
ret = clk_request(dev_clk, &clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk.id = periph;
|
||||
ret = clk_enable(&clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user