Merge branch 'master' of git://git.denx.de/u-boot-dm

This commit is contained in:
Tom Rini
2015-01-30 09:24:42 -05:00
185 changed files with 4646 additions and 1619 deletions

View File

@@ -88,6 +88,14 @@ int device_unbind(struct udevice *dev)
if (ret)
return ret;
if (dev->flags & DM_FLAG_ALLOC_PDATA) {
free(dev->platdata);
dev->platdata = NULL;
}
if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
free(dev->parent_platdata);
dev->parent_platdata = NULL;
}
ret = uclass_unbind_device(dev);
if (ret)
return ret;
@@ -111,10 +119,6 @@ void device_free(struct udevice *dev)
free(dev->priv);
dev->priv = NULL;
}
if (dev->flags & DM_FLAG_ALLOC_PDATA) {
free(dev->platdata);
dev->platdata = NULL;
}
size = dev->uclass->uc_drv->per_device_auto_alloc_size;
if (size) {
free(dev->uclass_priv);
@@ -122,6 +126,10 @@ void device_free(struct udevice *dev)
}
if (dev->parent) {
size = dev->parent->driver->per_child_auto_alloc_size;
if (!size) {
size = dev->parent->uclass->uc_drv->
per_child_auto_alloc_size;
}
if (size) {
free(dev->parent_priv);
dev->parent_priv = NULL;

View File

@@ -53,27 +53,47 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
dev->driver = drv;
dev->uclass = uc;
/*
* For some devices, such as a SPI or I2C bus, the 'reg' property
* is a reasonable indicator of the sequence number. But if there is
* an alias, we use that in preference. In any case, this is just
* a 'requested' sequence, and will be resolved (and ->seq updated)
* when the device is probed.
*/
dev->seq = -1;
#ifdef CONFIG_OF_CONTROL
dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
if (!IS_ERR_VALUE(dev->req_seq))
dev->req_seq &= INT_MAX;
if (uc->uc_drv->name && of_offset != -1) {
fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
&dev->req_seq);
}
#else
dev->req_seq = -1;
#ifdef CONFIG_OF_CONTROL
/*
* Some devices, such as a SPI bus, I2C bus and serial ports are
* numbered using aliases.
*
* This is just a 'requested' sequence, and will be
* resolved (and ->seq updated) when the device is probed.
*/
if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) {
if (uc->uc_drv->name && of_offset != -1) {
fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name,
of_offset, &dev->req_seq);
}
}
#endif
if (!dev->platdata && drv->platdata_auto_alloc_size)
if (!dev->platdata && drv->platdata_auto_alloc_size) {
dev->flags |= DM_FLAG_ALLOC_PDATA;
dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
if (!dev->platdata) {
ret = -ENOMEM;
goto fail_alloc1;
}
}
if (parent) {
int size = parent->driver->per_child_platdata_auto_alloc_size;
if (!size) {
size = parent->uclass->uc_drv->
per_child_platdata_auto_alloc_size;
}
if (size) {
dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
dev->parent_platdata = calloc(1, size);
if (!dev->parent_platdata) {
ret = -ENOMEM;
goto fail_alloc2;
}
}
}
/* put dev into parent's successor list */
if (parent)
@@ -81,28 +101,51 @@ int device_bind(struct udevice *parent, struct driver *drv, const char *name,
ret = uclass_bind_device(dev);
if (ret)
goto fail_bind;
goto fail_uclass_bind;
/* if we fail to bind we remove device from successors and free it */
if (drv->bind) {
ret = drv->bind(dev);
if (ret) {
if (uclass_unbind_device(dev)) {
dm_warn("Failed to unbind dev '%s' on error path\n",
dev->name);
}
if (ret)
goto fail_bind;
}
}
if (parent && parent->driver->child_post_bind) {
ret = parent->driver->child_post_bind(dev);
if (ret)
goto fail_child_post_bind;
}
if (parent)
dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
*devp = dev;
return 0;
fail_child_post_bind:
if (drv->unbind && drv->unbind(dev)) {
dm_warn("unbind() method failed on dev '%s' on error path\n",
dev->name);
}
fail_bind:
if (uclass_unbind_device(dev)) {
dm_warn("Failed to unbind dev '%s' on error path\n",
dev->name);
}
fail_uclass_bind:
list_del(&dev->sibling_node);
if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
free(dev->parent_platdata);
dev->parent_platdata = NULL;
}
fail_alloc2:
if (dev->flags & DM_FLAG_ALLOC_PDATA) {
free(dev->platdata);
dev->platdata = NULL;
}
fail_alloc1:
free(dev);
return ret;
}
@@ -137,7 +180,7 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
drv = dev->driver;
assert(drv);
/* Allocate private data and platdata if requested */
/* Allocate private data if requested */
if (drv->priv_auto_alloc_size) {
dev->priv = calloc(1, drv->priv_auto_alloc_size);
if (!dev->priv) {
@@ -146,13 +189,6 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
}
}
/* Allocate private data if requested */
if (dev->flags & DM_FLAG_ALLOC_PDATA) {
dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
if (!dev->platdata) {
ret = -ENOMEM;
goto fail;
}
}
size = dev->uclass->uc_drv->per_device_auto_alloc_size;
if (size) {
dev->uclass_priv = calloc(1, size);
@@ -165,6 +201,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
/* Ensure all parents are probed */
if (dev->parent) {
size = dev->parent->driver->per_child_auto_alloc_size;
if (!size) {
size = dev->parent->uclass->uc_drv->
per_child_auto_alloc_size;
}
if (size) {
dev->parent_priv = calloc(1, size);
if (!dev->parent_priv) {
@@ -187,6 +227,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
}
dev->seq = seq;
ret = uclass_pre_probe_child(dev);
if (ret)
goto fail;
if (dev->parent && dev->parent->driver->child_pre_probe) {
ret = dev->parent->driver->child_pre_probe(dev);
if (ret)
@@ -241,6 +285,16 @@ void *dev_get_platdata(struct udevice *dev)
return dev->platdata;
}
void *dev_get_parent_platdata(struct udevice *dev)
{
if (!dev) {
dm_warn("%s: null device", __func__);
return NULL;
}
return dev->parent_platdata;
}
void *dev_get_priv(struct udevice *dev)
{
if (!dev) {
@@ -390,3 +444,8 @@ ulong dev_get_of_data(struct udevice *dev)
{
return dev->of_id->data;
}
enum uclass_id device_get_uclass_id(struct udevice *dev)
{
return dev->uclass->uc_drv->id;
}

View File

@@ -9,6 +9,7 @@
#include <common.h>
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
#include <libfdt.h>
#include <dm/device.h>
@@ -49,6 +50,9 @@ int dm_init(void)
ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
if (ret)
return ret;
#ifdef CONFIG_OF_CONTROL
DM_ROOT_NON_CONST->of_offset = 0;
#endif
ret = device_probe(DM_ROOT_NON_CONST);
if (ret)
return ret;
@@ -89,6 +93,10 @@ int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
if (pre_reloc_only &&
!fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL))
continue;
if (!fdtdec_get_is_enabled(blob, offset)) {
dm_dbg(" - ignoring disabled device\n");
continue;
}
err = lists_bind_fdt(parent, blob, offset, NULL);
if (err && !ret)
ret = err;

View File

@@ -319,18 +319,29 @@ int uclass_bind_device(struct udevice *dev)
int ret;
uc = dev->uclass;
list_add_tail(&dev->uclass_node, &uc->dev_head);
if (dev->parent) {
struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv;
if (uc_drv->child_post_bind) {
ret = uc_drv->child_post_bind(dev);
if (ret)
goto err;
}
}
if (uc->uc_drv->post_bind) {
ret = uc->uc_drv->post_bind(dev);
if (ret) {
list_del(&dev->uclass_node);
return ret;
}
if (ret)
goto err;
}
return 0;
err:
/* There is no need to undo the parent's post_bind call */
list_del(&dev->uclass_node);
return ret;
}
int uclass_unbind_device(struct udevice *dev)
@@ -380,6 +391,19 @@ int uclass_resolve_seq(struct udevice *dev)
return seq;
}
int uclass_pre_probe_child(struct udevice *dev)
{
struct uclass_driver *uc_drv;
if (!dev->parent)
return 0;
uc_drv = dev->parent->uclass->uc_drv;
if (uc_drv->child_pre_probe)
return uc_drv->child_pre_probe(dev);
return 0;
}
int uclass_post_probe_device(struct udevice *dev)
{
struct uclass_driver *uc_drv = dev->uclass->uc_drv;

View File

@@ -0,0 +1 @@
source drivers/crypto/fsl/Kconfig

View File

@@ -6,4 +6,5 @@
#
obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o
obj-y += rsa_mod_exp/
obj-y += fsl/

View File

@@ -0,0 +1,6 @@
config FSL_CAAM
bool "Freescale Crypto Driver Support"
help
Enables the Freescale's Cryptographic Accelerator and Assurance
Module (CAAM), also known as the SEC version 4 (SEC4). The driver uses
Job Ring as interface to communicate with CAAM.

View File

@@ -9,3 +9,4 @@
obj-y += sec.o
obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o
obj-$(CONFIG_CMD_BLOB) += fsl_blob.o
obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o

View File

@@ -0,0 +1,60 @@
/*
* (C) Copyright 2014 Freescale Semiconductor, Inc.
* Author: Ruchika Gupta <ruchika.gupta@freescale.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
#include <dm.h>
#include <asm/types.h>
#include <malloc.h>
#include "jobdesc.h"
#include "desc.h"
#include "jr.h"
#include "rsa_caam.h"
#include <u-boot/rsa-mod-exp.h>
int fsl_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
struct key_prop *prop, uint8_t *out)
{
uint32_t keylen;
struct pk_in_params pkin;
uint32_t desc[MAX_CAAM_DESCSIZE];
int ret;
/* Length in bytes */
keylen = prop->num_bits / 8;
pkin.a = sig;
pkin.a_siz = sig_len;
pkin.n = prop->modulus;
pkin.n_siz = keylen;
pkin.e = prop->public_exponent;
pkin.e_siz = prop->exp_len;
inline_cnstr_jobdesc_pkha_rsaexp(desc, &pkin, out, sig_len);
ret = run_descriptor_jr(desc);
if (ret) {
debug("%s: RSA failed to verify: %d\n", __func__, ret);
return -EFAULT;
}
return 0;
}
static const struct mod_exp_ops fsl_mod_exp_ops = {
.mod_exp = fsl_mod_exp,
};
U_BOOT_DRIVER(fsl_rsa_mod_exp) = {
.name = "fsl_rsa_mod_exp",
.id = UCLASS_MOD_EXP,
.ops = &fsl_mod_exp_ops,
};
U_BOOT_DEVICE(fsl_rsa) = {
.name = "fsl_rsa_mod_exp",
};

View File

@@ -11,6 +11,7 @@
#include <common.h>
#include "desc_constr.h"
#include "jobdesc.h"
#include "rsa_caam.h"
#define KEY_BLOB_SIZE 32
#define MAC_SIZE 16
@@ -123,3 +124,30 @@ void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc)
append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
OP_ALG_RNG4_SK);
}
/* Change key size to bytes form bits in calling function*/
void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
struct pk_in_params *pkin, uint8_t *out,
uint32_t out_siz)
{
dma_addr_t dma_addr_e, dma_addr_a, dma_addr_n, dma_addr_out;
dma_addr_e = virt_to_phys((void *)pkin->e);
dma_addr_a = virt_to_phys((void *)pkin->a);
dma_addr_n = virt_to_phys((void *)pkin->n);
dma_addr_out = virt_to_phys((void *)out);
init_job_desc(desc, 0);
append_key(desc, dma_addr_e, pkin->e_siz, KEY_DEST_PKHA_E | CLASS_1);
append_fifo_load(desc, dma_addr_a,
pkin->a_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_A);
append_fifo_load(desc, dma_addr_n,
pkin->n_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_N);
append_operation(desc, OP_TYPE_PK | OP_ALG_PK | OP_ALG_PKMODE_MOD_EXPO);
append_fifo_store(desc, dma_addr_out, out_siz,
LDST_CLASS_1_CCB | FIFOST_TYPE_PKHA_B);
}

View File

@@ -10,6 +10,7 @@
#include <common.h>
#include <asm/io.h>
#include "rsa_caam.h"
#define KEY_IDNFR_SZ_BYTES 16
@@ -26,4 +27,8 @@ void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr,
uint32_t out_sz);
void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc);
void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
struct pk_in_params *pkin, uint8_t *out,
uint32_t out_siz);
#endif

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2014 Freescale Semiconductor, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __RSA_CAAM_H
#define __RSA_CAAM_H
#include <common.h>
/**
* struct pk_in_params - holder for input to PKHA block in CAAM
* These parameters are required to perform Modular Exponentiation
* using PKHA Block in CAAM
*/
struct pk_in_params {
const uint8_t *e; /* public exponent as byte array */
uint32_t e_siz; /* size of e[] in number of bytes */
const uint8_t *n; /* modulus as byte array */
uint32_t n_siz; /* size of n[] in number of bytes */
const uint8_t *a; /* Signature as byte array */
uint32_t a_siz; /* size of a[] in number of bytes */
uint8_t *b; /* Result exp. modulus in number of bytes */
uint32_t b_siz; /* size of b[] in number of bytes */
};
#endif

View File

@@ -0,0 +1,5 @@
config DM_MOD_EXP
bool "Enable Driver Model for RSA Modular Exponentiation"
depends on DM
help
If you want to use driver model for RSA Modular Exponentiation, say Y.

View File

@@ -0,0 +1,7 @@
#
# (C) Copyright 2014 Freescale Semiconductor, Inc.
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_RSA) += mod_exp_uclass.o mod_exp_sw.o

View File

@@ -0,0 +1,39 @@
/*
* (C) Copyright 2014 Freescale Semiconductor, Inc.
* Author: Ruchika Gupta <ruchika.gupta@freescale.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
#include <dm.h>
#include <u-boot/rsa-mod-exp.h>
int mod_exp_sw(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
struct key_prop *prop, uint8_t *out)
{
int ret = 0;
ret = rsa_mod_exp_sw(sig, sig_len, prop, out);
if (ret) {
debug("%s: RSA failed to verify: %d\n", __func__, ret);
return ret;
}
return 0;
}
static const struct mod_exp_ops mod_exp_ops_sw = {
.mod_exp = mod_exp_sw,
};
U_BOOT_DRIVER(mod_exp_sw) = {
.name = "mod_exp_sw",
.id = UCLASS_MOD_EXP,
.ops = &mod_exp_ops_sw,
};
U_BOOT_DEVICE(mod_exp_sw) = {
.name = "mod_exp_sw",
};

View File

@@ -0,0 +1,31 @@
/*
* (C) Copyright 2014 Freescale Semiconductor, Inc
* Author: Ruchika Gupta <ruchika.gupta@freescale.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <u-boot/rsa-mod-exp.h>
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
#include <asm/io.h>
#include <linux/list.h>
int rsa_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
struct key_prop *node, uint8_t *out)
{
const struct mod_exp_ops *ops = device_get_ops(dev);
if (!ops->mod_exp)
return -ENOSYS;
return ops->mod_exp(dev, sig, sig_len, node, out);
}
UCLASS_DRIVER(mod_exp) = {
.id = UCLASS_MOD_EXP,
.name = "rsa_mod_exp",
};

View File

@@ -11,6 +11,7 @@
#include <malloc.h>
#include <dm-demo.h>
#include <asm/io.h>
#include <asm/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -20,6 +21,8 @@ DECLARE_GLOBAL_DATA_PTR;
struct shape_data {
int num_chars; /* Number of non-space characters output so far */
struct gpio_desc gpio_desc[8];
int gpio_count;
};
/* Crazy little function to draw shapes on the console */
@@ -89,9 +92,52 @@ static int shape_status(struct udevice *dev, int *status)
return 0;
}
static int set_light(struct udevice *dev, int light)
{
struct shape_data *priv = dev_get_priv(dev);
struct gpio_desc *desc;
int ret;
int i;
desc = priv->gpio_desc;
for (i = 0; i < priv->gpio_count; i++, desc++) {
uint mask = 1 << i;
ret = dm_gpio_set_value(desc, light & mask);
if (ret < 0)
return ret;
}
return 0;
}
static int get_light(struct udevice *dev)
{
struct shape_data *priv = dev_get_priv(dev);
struct gpio_desc *desc;
uint value = 0;
int ret;
int i;
desc = priv->gpio_desc;
for (i = 0; i < priv->gpio_count; i++, desc++) {
uint mask = 1 << i;
ret = dm_gpio_get_value(desc);
if (ret < 0)
return ret;
if (ret)
value |= mask;
}
return value;
}
static const struct demo_ops shape_ops = {
.hello = shape_hello,
.status = shape_status,
.get_light = get_light,
.set_light = set_light,
};
static int shape_ofdata_to_platdata(struct udevice *dev)
@@ -111,6 +157,29 @@ static int shape_ofdata_to_platdata(struct udevice *dev)
return 0;
}
static int dm_shape_probe(struct udevice *dev)
{
struct shape_data *priv = dev_get_priv(dev);
int ret;
ret = gpio_request_list_by_name(dev, "light-gpios", priv->gpio_desc,
ARRAY_SIZE(priv->gpio_desc),
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
if (ret < 0)
return ret;
priv->gpio_count = ret;
debug("%s: %d GPIOs\n", __func__, priv->gpio_count);
return 0;
}
static int dm_shape_remove(struct udevice *dev)
{
struct shape_data *priv = dev_get_priv(dev);
return gpio_free_list(dev, priv->gpio_desc, priv->gpio_count);
}
static const struct udevice_id demo_shape_id[] = {
{ "demo-shape", 0 },
{ },
@@ -122,6 +191,8 @@ U_BOOT_DRIVER(demo_shape_drv) = {
.id = UCLASS_DEMO,
.ofdata_to_platdata = shape_ofdata_to_platdata,
.ops = &shape_ops,
.probe = dm_shape_probe,
.remove = dm_shape_remove,
.priv_auto_alloc_size = sizeof(struct shape_data),
.platdata_auto_alloc_size = sizeof(struct dm_demo_pdata),
};

View File

@@ -43,6 +43,26 @@ int demo_status(struct udevice *dev, int *status)
return ops->status(dev, status);
}
int demo_get_light(struct udevice *dev)
{
const struct demo_ops *ops = device_get_ops(dev);
if (!ops->get_light)
return -ENOSYS;
return ops->get_light(dev);
}
int demo_set_light(struct udevice *dev, int light)
{
const struct demo_ops *ops = device_get_ops(dev);
if (!ops->set_light)
return -ENOSYS;
return ops->set_light(dev, light);
}
int demo_parse_dt(struct udevice *dev)
{
struct dm_demo_pdata *pdata = dev_get_platdata(dev);

View File

@@ -7,20 +7,25 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <malloc.h>
#include <asm/gpio.h>
#include <linux/ctype.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* gpio_to_device() - Convert global GPIO number to device, number
* gpio: The numeric representation of the GPIO
*
* Convert the GPIO number to an entry in the list of GPIOs
* or GPIO blocks registered with the GPIO controller. Returns
* entry on success, NULL on error.
*
* @gpio: The numeric representation of the GPIO
* @desc: Returns description (desc->flags will always be 0)
* @return 0 if found, -ENOENT if not found
*/
static int gpio_to_device(unsigned int gpio, struct udevice **devp,
unsigned int *offset)
static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
{
struct gpio_dev_priv *uc_priv;
struct udevice *dev;
@@ -32,14 +37,15 @@ static int gpio_to_device(unsigned int gpio, struct udevice **devp,
uc_priv = dev->uclass_priv;
if (gpio >= uc_priv->gpio_base &&
gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
*devp = dev;
*offset = gpio - uc_priv->gpio_base;
desc->dev = dev;
desc->offset = gpio - uc_priv->gpio_base;
desc->flags = 0;
return 0;
}
}
/* No such GPIO */
return ret ? ret : -EINVAL;
return ret ? ret : -ENOENT;
}
int gpio_lookup_name(const char *name, struct udevice **devp,
@@ -88,6 +94,57 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
return 0;
}
static int gpio_find_and_xlate(struct gpio_desc *desc,
struct fdtdec_phandle_args *args)
{
struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
/* Use the first argument as the offset by default */
if (args->args_count > 0)
desc->offset = args->args[0];
else
desc->offset = -1;
desc->flags = 0;
return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0;
}
static int dm_gpio_request(struct gpio_desc *desc, const char *label)
{
struct udevice *dev = desc->dev;
struct gpio_dev_priv *uc_priv;
char *str;
int ret;
uc_priv = dev->uclass_priv;
if (uc_priv->name[desc->offset])
return -EBUSY;
str = strdup(label);
if (!str)
return -ENOMEM;
if (gpio_get_ops(dev)->request) {
ret = gpio_get_ops(dev)->request(dev, desc->offset, label);
if (ret) {
free(str);
return ret;
}
}
uc_priv->name[desc->offset] = str;
return 0;
}
static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...)
{
va_list args;
char buf[40];
va_start(args, fmt);
vscnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
return dm_gpio_request(desc, buf);
}
/**
* gpio_request() - [COMPAT] Request GPIO
* gpio: GPIO number
@@ -102,32 +159,14 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
*/
int gpio_request(unsigned gpio, const char *label)
{
struct gpio_dev_priv *uc_priv;
unsigned int offset;
struct udevice *dev;
char *str;
struct gpio_desc desc;
int ret;
ret = gpio_to_device(gpio, &dev, &offset);
ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
uc_priv = dev->uclass_priv;
if (uc_priv->name[offset])
return -EBUSY;
str = strdup(label);
if (!str)
return -ENOMEM;
if (gpio_get_ops(dev)->request) {
ret = gpio_get_ops(dev)->request(dev, offset, label);
if (ret) {
free(str);
return ret;
}
}
uc_priv->name[offset] = str;
return 0;
return dm_gpio_request(&desc, label);
}
/**
@@ -151,25 +190,11 @@ int gpio_requestf(unsigned gpio, const char *fmt, ...)
return gpio_request(gpio, buf);
}
/**
* gpio_free() - [COMPAT] Relinquish GPIO
* gpio: GPIO number
*
* This function implements the API that's compatible with current
* GPIO API used in U-Boot. The request is forwarded to particular
* GPIO driver. Returns 0 on success, negative value on error.
*/
int gpio_free(unsigned gpio)
int _dm_gpio_free(struct udevice *dev, uint offset)
{
struct gpio_dev_priv *uc_priv;
unsigned int offset;
struct udevice *dev;
int ret;
ret = gpio_to_device(gpio, &dev, &offset);
if (ret)
return ret;
uc_priv = dev->uclass_priv;
if (!uc_priv->name[offset])
return -ENXIO;
@@ -185,15 +210,35 @@ int gpio_free(unsigned gpio)
return 0;
}
static int check_reserved(struct udevice *dev, unsigned offset,
const char *func)
/**
* gpio_free() - [COMPAT] Relinquish GPIO
* gpio: GPIO number
*
* This function implements the API that's compatible with current
* GPIO API used in U-Boot. The request is forwarded to particular
* GPIO driver. Returns 0 on success, negative value on error.
*/
int gpio_free(unsigned gpio)
{
struct gpio_dev_priv *uc_priv = dev->uclass_priv;
struct gpio_desc desc;
int ret;
if (!uc_priv->name[offset]) {
ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
return _dm_gpio_free(desc.dev, desc.offset);
}
static int check_reserved(struct gpio_desc *desc, const char *func)
{
struct gpio_dev_priv *uc_priv = desc->dev->uclass_priv;
if (!uc_priv->name[desc->offset]) {
printf("%s: %s: error: gpio %s%d not reserved\n",
dev->name, func,
uc_priv->bank_name ? uc_priv->bank_name : "", offset);
desc->dev->name, func,
uc_priv->bank_name ? uc_priv->bank_name : "",
desc->offset);
return -EBUSY;
}
@@ -210,16 +255,17 @@ static int check_reserved(struct udevice *dev, unsigned offset,
*/
int gpio_direction_input(unsigned gpio)
{
unsigned int offset;
struct udevice *dev;
struct gpio_desc desc;
int ret;
ret = gpio_to_device(gpio, &dev, &offset);
ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
ret = check_reserved(&desc, "dir_input");
if (ret)
return ret;
ret = check_reserved(dev, offset, "dir_input");
return ret ? ret : gpio_get_ops(dev)->direction_input(dev, offset);
return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset);
}
/**
@@ -233,17 +279,81 @@ int gpio_direction_input(unsigned gpio)
*/
int gpio_direction_output(unsigned gpio, int value)
{
unsigned int offset;
struct udevice *dev;
struct gpio_desc desc;
int ret;
ret = gpio_to_device(gpio, &dev, &offset);
ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
ret = check_reserved(&desc, "dir_output");
if (ret)
return ret;
ret = check_reserved(dev, offset, "dir_output");
return ret ? ret :
gpio_get_ops(dev)->direction_output(dev, offset, value);
return gpio_get_ops(desc.dev)->direction_output(desc.dev,
desc.offset, value);
}
int dm_gpio_get_value(struct gpio_desc *desc)
{
int value;
int ret;
ret = check_reserved(desc, "get_value");
if (ret)
return ret;
value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
}
int dm_gpio_set_value(struct gpio_desc *desc, int value)
{
int ret;
ret = check_reserved(desc, "set_value");
if (ret)
return ret;
if (desc->flags & GPIOD_ACTIVE_LOW)
value = !value;
gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
return 0;
}
int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
{
struct udevice *dev = desc->dev;
struct dm_gpio_ops *ops = gpio_get_ops(dev);
int ret;
ret = check_reserved(desc, "set_dir");
if (ret)
return ret;
if (flags & GPIOD_IS_OUT) {
int value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
if (flags & GPIOD_ACTIVE_LOW)
value = !value;
ret = ops->direction_output(dev, desc->offset, value);
} else if (flags & GPIOD_IS_IN) {
ret = ops->direction_input(dev, desc->offset);
}
if (ret)
return ret;
/*
* Update desc->flags here, so that GPIO_ACTIVE_LOW is honoured in
* futures
*/
desc->flags = flags;
return 0;
}
int dm_gpio_set_dir(struct gpio_desc *desc)
{
return dm_gpio_set_dir_flags(desc, desc->flags);
}
/**
@@ -257,16 +367,14 @@ int gpio_direction_output(unsigned gpio, int value)
*/
int gpio_get_value(unsigned gpio)
{
unsigned int offset;
struct udevice *dev;
int ret;
ret = gpio_to_device(gpio, &dev, &offset);
struct gpio_desc desc;
ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
ret = check_reserved(dev, offset, "get_value");
return ret ? ret : gpio_get_ops(dev)->get_value(dev, offset);
return dm_gpio_get_value(&desc);
}
/**
@@ -280,16 +388,13 @@ int gpio_get_value(unsigned gpio)
*/
int gpio_set_value(unsigned gpio, int value)
{
unsigned int offset;
struct udevice *dev;
struct gpio_desc desc;
int ret;
ret = gpio_to_device(gpio, &dev, &offset);
ret = gpio_to_device(gpio, &desc);
if (ret)
return ret;
ret = check_reserved(dev, offset, "set_value");
return ret ? ret : gpio_get_ops(dev)->set_value(dev, offset, value);
return dm_gpio_set_value(&desc, value);
}
const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
@@ -409,6 +514,155 @@ unsigned gpio_get_values_as_int(const int *gpio_num_array)
return vector;
}
static int _gpio_request_by_name_nodev(const void *blob, int node,
const char *list_name, int index,
struct gpio_desc *desc, int flags,
bool add_index)
{
struct fdtdec_phandle_args args;
int ret;
desc->dev = NULL;
desc->offset = 0;
ret = fdtdec_parse_phandle_with_args(blob, node, list_name,
"#gpio-cells", 0, index, &args);
if (ret) {
debug("%s: fdtdec_parse_phandle_with_args failed\n", __func__);
goto err;
}
ret = uclass_get_device_by_of_offset(UCLASS_GPIO, args.node,
&desc->dev);
if (ret) {
debug("%s: uclass_get_device_by_of_offset failed\n", __func__);
goto err;
}
ret = gpio_find_and_xlate(desc, &args);
if (ret) {
debug("%s: gpio_find_and_xlate failed\n", __func__);
goto err;
}
ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s",
fdt_get_name(blob, node, NULL),
list_name, index);
if (ret) {
debug("%s: dm_gpio_requestf failed\n", __func__);
goto err;
}
ret = dm_gpio_set_dir_flags(desc, flags | desc->flags);
if (ret) {
debug("%s: dm_gpio_set_dir failed\n", __func__);
goto err;
}
return 0;
err:
debug("%s: Node '%s', property '%s', failed to request GPIO index %d: %d\n",
__func__, fdt_get_name(blob, node, NULL), list_name, index, ret);
return ret;
}
int gpio_request_by_name_nodev(const void *blob, int node,
const char *list_name, int index,
struct gpio_desc *desc, int flags)
{
return _gpio_request_by_name_nodev(blob, node, list_name, index, desc,
flags, index > 0);
}
int gpio_request_by_name(struct udevice *dev, const char *list_name, int index,
struct gpio_desc *desc, int flags)
{
/*
* This isn't ideal since we don't use dev->name in the debug()
* calls in gpio_request_by_name(), but we can do this until
* gpio_request_by_name_nodev() can be dropped.
*/
return gpio_request_by_name_nodev(gd->fdt_blob, dev->of_offset,
list_name, index, desc, flags);
}
int gpio_request_list_by_name_nodev(const void *blob, int node,
const char *list_name,
struct gpio_desc *desc, int max_count,
int flags)
{
int count;
int ret;
for (count = 0; ; count++) {
if (count >= max_count) {
ret = -ENOSPC;
goto err;
}
ret = _gpio_request_by_name_nodev(blob, node, list_name, count,
&desc[count], flags, true);
if (ret == -ENOENT)
break;
else if (ret)
goto err;
}
/* We ran out of GPIOs in the list */
return count;
err:
gpio_free_list_nodev(desc, count - 1);
return ret;
}
int gpio_request_list_by_name(struct udevice *dev, const char *list_name,
struct gpio_desc *desc, int max_count,
int flags)
{
/*
* This isn't ideal since we don't use dev->name in the debug()
* calls in gpio_request_by_name(), but we can do this until
* gpio_request_list_by_name_nodev() can be dropped.
*/
return gpio_request_list_by_name_nodev(gd->fdt_blob, dev->of_offset,
list_name, desc, max_count,
flags);
}
int gpio_get_list_count(struct udevice *dev, const char *list_name)
{
int ret;
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
list_name, "#gpio-cells", 0, -1,
NULL);
if (ret) {
debug("%s: Node '%s', property '%s', GPIO count failed: %d\n",
__func__, dev->name, list_name, ret);
}
return ret;
}
int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
{
/* For now, we don't do any checking of dev */
return _dm_gpio_free(desc->dev, desc->offset);
}
int gpio_free_list(struct udevice *dev, struct gpio_desc *desc, int count)
{
int i;
/* For now, we don't do any checking of dev */
for (i = 0; i < count; i++)
dm_gpio_free(dev, &desc[i]);
return 0;
}
int gpio_free_list_nodev(struct gpio_desc *desc, int count)
{
return gpio_free_list(NULL, desc, count);
}
/* We need to renumber the GPIOs when any driver is probed/removed */
static int gpio_renumber(struct udevice *removed_dev)
{

View File

@@ -13,6 +13,7 @@
#include <asm/io.h>
#include <asm/gpio.h>
#include <dm/device-internal.h>
#include <dt-bindings/gpio/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -275,12 +276,22 @@ static int exynos_gpio_get_function(struct udevice *dev, unsigned offset)
return GPIOF_FUNC;
}
static int exynos_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
struct fdtdec_phandle_args *args)
{
desc->offset = args->args[0];
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
return 0;
}
static const struct dm_gpio_ops gpio_exynos_ops = {
.direction_input = exynos_gpio_direction_input,
.direction_output = exynos_gpio_direction_output,
.get_value = exynos_gpio_get_value,
.set_value = exynos_gpio_set_value,
.get_function = exynos_gpio_get_function,
.xlate = exynos_gpio_xlate,
};
static int gpio_exynos_probe(struct udevice *dev)
@@ -342,7 +353,7 @@ static int gpio_exynos_bind(struct udevice *parent)
plat->bank_name, plat, -1, &dev);
if (ret)
return ret;
dev->of_offset = parent->of_offset;
dev->of_offset = node;
}
return 0;

View File

@@ -8,6 +8,7 @@
#include <fdtdec.h>
#include <malloc.h>
#include <asm/gpio.h>
#include <dt-bindings/gpio/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -130,12 +131,31 @@ static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
return GPIOF_INPUT;
}
static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
struct fdtdec_phandle_args *args)
{
desc->offset = args->args[0];
if (args->args_count < 2)
return 0;
if (args->args[1] & GPIO_ACTIVE_LOW)
desc->flags |= GPIOD_ACTIVE_LOW;
if (args->args[1] & 2)
desc->flags |= GPIOD_IS_IN;
if (args->args[1] & 4)
desc->flags |= GPIOD_IS_OUT;
if (args->args[1] & 8)
desc->flags |= GPIOD_IS_OUT_ACTIVE;
return 0;
}
static const struct dm_gpio_ops gpio_sandbox_ops = {
.direction_input = sb_gpio_direction_input,
.direction_output = sb_gpio_direction_output,
.get_value = sb_gpio_get_value,
.set_value = sb_gpio_set_value,
.get_function = sb_gpio_get_function,
.xlate = sb_gpio_xlate,
};
static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)

View File

@@ -21,6 +21,7 @@
#include <asm/arch/tegra.h>
#include <asm/gpio.h>
#include <dm/device-internal.h>
#include <dt-bindings/gpio/gpio.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -251,6 +252,22 @@ static int tegra_gpio_get_function(struct udevice *dev, unsigned offset)
return GPIOF_INPUT;
}
static int tegra_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
struct fdtdec_phandle_args *args)
{
int gpio, port, ret;
gpio = args->args[0];
port = gpio / TEGRA_GPIOS_PER_PORT;
ret = device_get_child(dev, port, &desc->dev);
if (ret)
return ret;
desc->offset = gpio % TEGRA_GPIOS_PER_PORT;
desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
return 0;
}
static const struct dm_gpio_ops gpio_tegra_ops = {
.request = tegra_gpio_request,
.direction_input = tegra_gpio_direction_input,
@@ -258,6 +275,7 @@ static const struct dm_gpio_ops gpio_tegra_ops = {
.get_value = tegra_gpio_get_value,
.set_value = tegra_gpio_set_value,
.get_function = tegra_gpio_get_function,
.xlate = tegra_gpio_xlate,
};
/**

View File

@@ -0,0 +1,22 @@
config DM_I2C
bool "Enable Driver Model for I2C drivers"
depends on DM
help
If you want to use driver model for I2C drivers, say Y.
To use legacy I2C drivers, say N.
config SYS_I2C_UNIPHIER
bool "UniPhier I2C driver"
depends on ARCH_UNIPHIER && DM_I2C
default y
help
Support for Panasonic UniPhier I2C controller driver. This I2C
controller is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs.
config SYS_I2C_UNIPHIER_F
bool "UniPhier FIFO-builtin I2C driver"
depends on ARCH_UNIPHIER && DM_I2C
default y
help
Support for Panasonic UniPhier FIFO-builtin I2C controller driver.
This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs.

View File

@@ -5,6 +5,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_DM_I2C) += i2c-uclass.o
obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
obj-$(CONFIG_I2C_MV) += mv_i2c.o
@@ -31,4 +32,6 @@ obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2014 Google, Inc
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <i2c.h>
static int cur_busnum;
static int i2c_compat_get_device(uint chip_addr, int alen,
struct udevice **devp)
{
struct dm_i2c_chip *chip;
int ret;
ret = i2c_get_chip_for_busnum(cur_busnum, chip_addr, alen, devp);
if (ret)
return ret;
chip = dev_get_parent_platdata(*devp);
if (chip->offset_len != alen) {
printf("I2C chip %x: requested alen %d does not match chip offset_len %d\n",
chip_addr, alen, chip->offset_len);
return -EADDRNOTAVAIL;
}
return 0;
}
int i2c_probe(uint8_t chip_addr)
{
struct udevice *bus, *dev;
int ret;
ret = uclass_get_device_by_seq(UCLASS_I2C, cur_busnum, &bus);
if (ret) {
debug("Cannot find I2C bus %d: err=%d\n", cur_busnum, ret);
return ret;
}
if (!bus)
return -ENOENT;
return dm_i2c_probe(bus, chip_addr, 0, &dev);
}
int i2c_read(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
int len)
{
struct udevice *dev;
int ret;
ret = i2c_compat_get_device(chip_addr, alen, &dev);
if (ret)
return ret;
return dm_i2c_read(dev, addr, buffer, len);
}
int i2c_write(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
int len)
{
struct udevice *dev;
int ret;
ret = i2c_compat_get_device(chip_addr, alen, &dev);
if (ret)
return ret;
return dm_i2c_write(dev, addr, buffer, len);
}
int i2c_get_bus_num_fdt(int node)
{
struct udevice *bus;
int ret;
ret = uclass_get_device_by_of_offset(UCLASS_I2C, node, &bus);
if (ret)
return ret;
return bus->seq;
}
unsigned int i2c_get_bus_num(void)
{
return cur_busnum;
}
int i2c_set_bus_num(unsigned int bus)
{
cur_busnum = bus;
return 0;
}
void i2c_init(int speed, int slaveaddr)
{
/* Nothing to do here - the init happens through driver model */
}
void board_i2c_init(const void *blob)
{
/* Nothing to do here - the init happens through driver model */
}

View File

@@ -50,7 +50,7 @@ static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset,
static int i2c_read_bytewise(struct udevice *dev, uint offset,
uint8_t *buffer, int len)
{
struct dm_i2c_chip *chip = dev_get_parentdata(dev);
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
@@ -79,7 +79,7 @@ static int i2c_read_bytewise(struct udevice *dev, uint offset,
static int i2c_write_bytewise(struct udevice *dev, uint offset,
const uint8_t *buffer, int len)
{
struct dm_i2c_chip *chip = dev_get_parentdata(dev);
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
@@ -100,9 +100,9 @@ static int i2c_write_bytewise(struct udevice *dev, uint offset,
return 0;
}
int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
{
struct dm_i2c_chip *chip = dev_get_parentdata(dev);
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
@@ -130,9 +130,10 @@ int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
return ops->xfer(bus, msg, msg_count);
}
int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len)
int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
int len)
{
struct dm_i2c_chip *chip = dev_get_parentdata(dev);
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
@@ -219,10 +220,10 @@ static int i2c_probe_chip(struct udevice *bus, uint chip_addr,
return ops->xfer(bus, msg, 1);
}
static int i2c_bind_driver(struct udevice *bus, uint chip_addr,
static int i2c_bind_driver(struct udevice *bus, uint chip_addr, uint offset_len,
struct udevice **devp)
{
struct dm_i2c_chip chip;
struct dm_i2c_chip *chip;
char name[30], *str;
struct udevice *dev;
int ret;
@@ -235,11 +236,11 @@ static int i2c_bind_driver(struct udevice *bus, uint chip_addr,
goto err_bind;
/* Tell the device what we know about it */
memset(&chip, '\0', sizeof(chip));
chip.chip_addr = chip_addr;
chip.offset_len = 1; /* we assume */
ret = device_probe_child(dev, &chip);
debug("%s: device_probe_child: ret=%d\n", __func__, ret);
chip = dev_get_parent_platdata(dev);
chip->chip_addr = chip_addr;
chip->offset_len = offset_len;
ret = device_probe(dev);
debug("%s: device_probe: ret=%d\n", __func__, ret);
if (ret)
goto err_probe;
@@ -247,13 +248,18 @@ static int i2c_bind_driver(struct udevice *bus, uint chip_addr,
return 0;
err_probe:
/*
* If the device failed to probe, unbind it. There is nothing there
* on the bus so we don't want to leave it lying around
*/
device_unbind(dev);
err_bind:
free(str);
return ret;
}
int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
int i2c_get_chip(struct udevice *bus, uint chip_addr, uint offset_len,
struct udevice **devp)
{
struct udevice *dev;
@@ -261,15 +267,9 @@ int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
bus->name, chip_addr);
for (device_find_first_child(bus, &dev); dev;
device_find_next_child(&dev)) {
struct dm_i2c_chip store;
struct dm_i2c_chip *chip = dev_get_parentdata(dev);
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
int ret;
if (!chip) {
chip = &store;
i2c_chip_ofdata_to_platdata(gd->fdt_blob,
dev->of_offset, chip);
}
if (chip->chip_addr == chip_addr) {
ret = device_probe(dev);
debug("found, ret=%d\n", ret);
@@ -280,10 +280,11 @@ int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
}
}
debug("not found\n");
return i2c_bind_driver(bus, chip_addr, devp);
return i2c_bind_driver(bus, chip_addr, offset_len, devp);
}
int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)
int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len,
struct udevice **devp)
{
struct udevice *bus;
int ret;
@@ -293,7 +294,7 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)
debug("Cannot find I2C bus %d\n", busnum);
return ret;
}
ret = i2c_get_chip(bus, chip_addr, devp);
ret = i2c_get_chip(bus, chip_addr, offset_len, devp);
if (ret) {
debug("Cannot find I2C chip %02x on bus %d\n", chip_addr,
busnum);
@@ -303,8 +304,8 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)
return 0;
}
int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
struct udevice **devp)
int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
struct udevice **devp)
{
int ret;
@@ -318,7 +319,7 @@ int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
return ret;
/* The chip was found, see if we have a driver, and probe it */
ret = i2c_get_chip(bus, chip_addr, devp);
ret = i2c_get_chip(bus, chip_addr, 1, devp);
debug("%s: i2c_get_chip: ret=%d\n", __func__, ret);
return ret;
@@ -364,7 +365,7 @@ int i2c_get_bus_speed(struct udevice *bus)
int i2c_set_chip_flags(struct udevice *dev, uint flags)
{
struct udevice *bus = dev->parent;
struct dm_i2c_chip *chip = dev_get_parentdata(dev);
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
int ret;
@@ -380,7 +381,7 @@ int i2c_set_chip_flags(struct udevice *dev, uint flags)
int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
{
struct dm_i2c_chip *chip = dev_get_parentdata(dev);
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
*flagsp = chip->flags;
@@ -389,7 +390,7 @@ int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
{
struct dm_i2c_chip *chip = dev_get_parentdata(dev);
struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
if (offset_len > I2C_MAX_OFFSET_LEN)
return -EINVAL;
@@ -419,7 +420,8 @@ int i2c_deblock(struct udevice *bus)
int i2c_chip_ofdata_to_platdata(const void *blob, int node,
struct dm_i2c_chip *chip)
{
chip->offset_len = 1; /* default */
chip->offset_len = fdtdec_get_int(gd->fdt_blob, node,
"u-boot,i2c-offset-len", 1);
chip->flags = 0;
chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1);
if (chip->chip_addr == -1) {
@@ -441,18 +443,31 @@ static int i2c_post_probe(struct udevice *dev)
return i2c_set_bus_speed(dev, i2c->speed_hz);
}
int i2c_post_bind(struct udevice *dev)
static int i2c_post_bind(struct udevice *dev)
{
/* Scan the bus for devices */
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
static int i2c_child_post_bind(struct udevice *dev)
{
struct dm_i2c_chip *plat = dev_get_parent_platdata(dev);
if (dev->of_offset == -1)
return 0;
return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
}
UCLASS_DRIVER(i2c) = {
.id = UCLASS_I2C,
.name = "i2c",
.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = i2c_post_bind,
.post_probe = i2c_post_probe,
.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
.per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),
.child_post_bind = i2c_child_post_bind,
};
UCLASS_DRIVER(i2c_generic) = {

View File

@@ -0,0 +1,367 @@
/*
* Copyright (C) 2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <dm/device.h>
#include <dm/root.h>
#include <i2c.h>
#include <fdtdec.h>
DECLARE_GLOBAL_DATA_PTR;
struct uniphier_fi2c_regs {
u32 cr; /* control register */
#define I2C_CR_MST (1 << 3) /* master mode */
#define I2C_CR_STA (1 << 2) /* start condition */
#define I2C_CR_STO (1 << 1) /* stop condition */
#define I2C_CR_NACK (1 << 0) /* not ACK */
u32 dttx; /* send FIFO (write-only) */
#define dtrx dttx /* receive FIFO (read-only) */
#define I2C_DTTX_CMD (1 << 8) /* send command (slave addr) */
#define I2C_DTTX_RD (1 << 0) /* read */
u32 __reserved; /* no register at offset 0x08 */
u32 slad; /* slave address */
u32 cyc; /* clock cycle control */
u32 lctl; /* clock low period control */
u32 ssut; /* restart/stop setup time control */
u32 dsut; /* data setup time control */
u32 intr; /* interrupt status */
u32 ie; /* interrupt enable */
u32 ic; /* interrupt clear */
#define I2C_INT_TE (1 << 9) /* TX FIFO empty */
#define I2C_INT_RB (1 << 4) /* received specified bytes */
#define I2C_INT_NA (1 << 2) /* no answer */
#define I2C_INT_AL (1 << 1) /* arbitration lost */
u32 sr; /* status register */
#define I2C_SR_DB (1 << 12) /* device busy */
#define I2C_SR_BB (1 << 8) /* bus busy */
#define I2C_SR_RFF (1 << 3) /* Rx FIFO full */
#define I2C_SR_RNE (1 << 2) /* Rx FIFO not empty */
#define I2C_SR_TNF (1 << 1) /* Tx FIFO not full */
#define I2C_SR_TFE (1 << 0) /* Tx FIFO empty */
u32 __reserved2; /* no register at offset 0x30 */
u32 rst; /* reset control */
#define I2C_RST_TBRST (1 << 2) /* clear Tx FIFO */
#define I2C_RST_RBRST (1 << 1) /* clear Rx FIFO */
#define I2C_RST_RST (1 << 0) /* forcible bus reset */
u32 bm; /* bus monitor */
u32 noise; /* noise filter control */
u32 tbc; /* Tx byte count setting */
u32 rbc; /* Rx byte count setting */
u32 tbcm; /* Tx byte count monitor */
u32 rbcm; /* Rx byte count monitor */
u32 brst; /* bus reset */
#define I2C_BRST_FOEN (1 << 1) /* normal operation */
#define I2C_BRST_RSCLO (1 << 0) /* release SCL low fixing */
};
#define FIOCLK 50000000
struct uniphier_fi2c_dev {
struct uniphier_fi2c_regs __iomem *regs; /* register base */
unsigned long fioclk; /* internal operation clock */
unsigned long timeout; /* time out (us) */
};
static int poll_status(u32 __iomem *reg, u32 flag)
{
int wait = 1000000; /* 1 sec is long enough */
while (readl(reg) & flag) {
if (wait-- < 0)
return -EREMOTEIO;
udelay(1);
}
return 0;
}
static int reset_bus(struct uniphier_fi2c_regs __iomem *regs)
{
int ret;
/* bus forcible reset */
writel(I2C_RST_RST, &regs->rst);
ret = poll_status(&regs->rst, I2C_RST_RST);
if (ret < 0)
debug("error: fail to reset I2C controller\n");
return ret;
}
static int check_device_busy(struct uniphier_fi2c_regs __iomem *regs)
{
int ret;
ret = poll_status(&regs->sr, I2C_SR_DB);
if (ret < 0) {
debug("error: device busy too long. reset...\n");
ret = reset_bus(regs);
}
return ret;
}
static int uniphier_fi2c_probe(struct udevice *dev)
{
fdt_addr_t addr;
fdt_size_t size;
struct uniphier_fi2c_dev *priv = dev_get_priv(dev);
int ret;
addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg",
&size);
priv->regs = map_sysmem(addr, size);
if (!priv->regs)
return -ENOMEM;
priv->fioclk = FIOCLK;
/* bus forcible reset */
ret = reset_bus(priv->regs);
if (ret < 0)
return ret;
writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &priv->regs->brst);
return 0;
}
static int uniphier_fi2c_remove(struct udevice *dev)
{
struct uniphier_fi2c_dev *priv = dev_get_priv(dev);
unmap_sysmem(priv->regs);
return 0;
}
static int wait_for_irq(struct uniphier_fi2c_dev *dev, u32 flags,
bool *stop)
{
u32 irq;
unsigned long wait = dev->timeout;
int ret = -EREMOTEIO;
do {
udelay(1);
irq = readl(&dev->regs->intr);
} while (!(irq & flags) && wait--);
if (wait < 0) {
debug("error: time out\n");
return ret;
}
if (irq & I2C_INT_AL) {
debug("error: arbitration lost\n");
*stop = false;
return ret;
}
if (irq & I2C_INT_NA) {
debug("error: no answer\n");
return ret;
}
return 0;
}
static int issue_stop(struct uniphier_fi2c_dev *dev, int old_ret)
{
int ret;
debug("stop condition\n");
writel(I2C_CR_MST | I2C_CR_STO, &dev->regs->cr);
ret = poll_status(&dev->regs->sr, I2C_SR_DB);
if (ret < 0)
debug("error: device busy after operation\n");
return old_ret ? old_ret : ret;
}
static int uniphier_fi2c_transmit(struct uniphier_fi2c_dev *dev, uint addr,
uint len, const u8 *buf, bool *stop)
{
int ret;
const u32 irq_flags = I2C_INT_TE | I2C_INT_NA | I2C_INT_AL;
struct uniphier_fi2c_regs __iomem *regs = dev->regs;
debug("%s: addr = %x, len = %d\n", __func__, addr, len);
writel(I2C_DTTX_CMD | addr << 1, &regs->dttx);
writel(irq_flags, &regs->ie);
writel(irq_flags, &regs->ic);
debug("start condition\n");
writel(I2C_CR_MST | I2C_CR_STA, &regs->cr);
ret = wait_for_irq(dev, irq_flags, stop);
if (ret < 0)
goto error;
while (len--) {
debug("sending %x\n", *buf);
writel(*buf++, &regs->dttx);
writel(irq_flags, &regs->ic);
ret = wait_for_irq(dev, irq_flags, stop);
if (ret < 0)
goto error;
}
error:
writel(irq_flags, &regs->ic);
if (*stop)
ret = issue_stop(dev, ret);
return ret;
}
static int uniphier_fi2c_receive(struct uniphier_fi2c_dev *dev, uint addr,
uint len, u8 *buf, bool *stop)
{
int ret = 0;
const u32 irq_flags = I2C_INT_RB | I2C_INT_NA | I2C_INT_AL;
struct uniphier_fi2c_regs __iomem *regs = dev->regs;
debug("%s: addr = %x, len = %d\n", __func__, addr, len);
/*
* In case 'len == 0', only the slave address should be sent
* for probing, which is covered by the transmit function.
*/
if (len == 0)
return uniphier_fi2c_transmit(dev, addr, len, buf, stop);
writel(I2C_DTTX_CMD | I2C_DTTX_RD | addr << 1, &regs->dttx);
writel(0, &regs->rbc);
writel(irq_flags, &regs->ie);
writel(irq_flags, &regs->ic);
debug("start condition\n");
writel(I2C_CR_MST | I2C_CR_STA | (len == 1 ? I2C_CR_NACK : 0),
&regs->cr);
while (len--) {
ret = wait_for_irq(dev, irq_flags, stop);
if (ret < 0)
goto error;
*buf++ = readl(&regs->dtrx);
debug("received %x\n", *(buf - 1));
if (len == 1)
writel(I2C_CR_MST | I2C_CR_NACK, &regs->cr);
writel(irq_flags, &regs->ic);
}
error:
writel(irq_flags, &regs->ic);
if (*stop)
ret = issue_stop(dev, ret);
return ret;
}
static int uniphier_fi2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
int ret;
struct uniphier_fi2c_dev *dev = dev_get_priv(bus);
bool stop;
ret = check_device_busy(dev->regs);
if (ret < 0)
return ret;
for (; nmsgs > 0; nmsgs--, msg++) {
/* If next message is read, skip the stop condition */
stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
if (msg->flags & I2C_M_RD)
ret = uniphier_fi2c_receive(dev, msg->addr, msg->len,
msg->buf, &stop);
else
ret = uniphier_fi2c_transmit(dev, msg->addr, msg->len,
msg->buf, &stop);
if (ret < 0)
break;
}
return ret;
}
static int uniphier_fi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
int ret;
unsigned int clk_count;
struct uniphier_fi2c_dev *dev = dev_get_priv(bus);
struct uniphier_fi2c_regs __iomem *regs = dev->regs;
/* max supported frequency is 400 kHz */
if (speed > 400000)
return -EINVAL;
ret = check_device_busy(dev->regs);
if (ret < 0)
return ret;
/* make sure the bus is idle when changing the frequency */
writel(I2C_BRST_RSCLO, &regs->brst);
clk_count = dev->fioclk / speed;
writel(clk_count, &regs->cyc);
writel(clk_count / 2, &regs->lctl);
writel(clk_count / 2, &regs->ssut);
writel(clk_count / 16, &regs->dsut);
writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &regs->brst);
/*
* Theoretically, each byte can be transferred in
* 1000000 * 9 / speed usec.
* This time out value is long enough.
*/
dev->timeout = 100000000L / speed;
return 0;
}
static const struct dm_i2c_ops uniphier_fi2c_ops = {
.xfer = uniphier_fi2c_xfer,
.set_bus_speed = uniphier_fi2c_set_bus_speed,
};
static const struct udevice_id uniphier_fi2c_of_match[] = {
{ .compatible = "panasonic,uniphier-fi2c" },
{},
};
U_BOOT_DRIVER(uniphier_fi2c) = {
.name = "uniphier-fi2c",
.id = UCLASS_I2C,
.of_match = uniphier_fi2c_of_match,
.probe = uniphier_fi2c_probe,
.remove = uniphier_fi2c_remove,
.priv_auto_alloc_size = sizeof(struct uniphier_fi2c_dev),
.ops = &uniphier_fi2c_ops,
};

227
drivers/i2c/i2c-uniphier.c Normal file
View File

@@ -0,0 +1,227 @@
/*
* Copyright (C) 2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <dm/device.h>
#include <dm/root.h>
#include <i2c.h>
#include <fdtdec.h>
DECLARE_GLOBAL_DATA_PTR;
struct uniphier_i2c_regs {
u32 dtrm; /* data transmission */
#define I2C_DTRM_STA (1 << 10)
#define I2C_DTRM_STO (1 << 9)
#define I2C_DTRM_NACK (1 << 8)
#define I2C_DTRM_RD (1 << 0)
u32 drec; /* data reception */
#define I2C_DREC_STS (1 << 12)
#define I2C_DREC_LRB (1 << 11)
#define I2C_DREC_LAB (1 << 9)
u32 myad; /* slave address */
u32 clk; /* clock frequency control */
u32 brst; /* bus reset */
#define I2C_BRST_FOEN (1 << 1)
#define I2C_BRST_BRST (1 << 0)
u32 hold; /* hold time control */
u32 bsts; /* bus status monitor */
u32 noise; /* noise filter control */
u32 setup; /* setup time control */
};
#define IOBUS_FREQ 100000000
struct uniphier_i2c_dev {
struct uniphier_i2c_regs __iomem *regs; /* register base */
unsigned long input_clk; /* master clock (Hz) */
unsigned long wait_us; /* wait for every byte transfer (us) */
};
static int uniphier_i2c_probe(struct udevice *dev)
{
fdt_addr_t addr;
fdt_size_t size;
struct uniphier_i2c_dev *priv = dev_get_priv(dev);
addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
priv->regs = map_sysmem(addr, size);
if (!priv->regs)
return -ENOMEM;
priv->input_clk = IOBUS_FREQ;
/* deassert reset */
writel(0x3, &priv->regs->brst);
return 0;
}
static int uniphier_i2c_remove(struct udevice *dev)
{
struct uniphier_i2c_dev *priv = dev_get_priv(dev);
unmap_sysmem(priv->regs);
return 0;
}
static int send_and_recv_byte(struct uniphier_i2c_dev *dev, u32 dtrm)
{
writel(dtrm, &dev->regs->dtrm);
/*
* This controller only provides interruption to inform the completion
* of each byte transfer. (No status register to poll it.)
* Unfortunately, U-Boot does not have a good support of interrupt.
* Wait for a while.
*/
udelay(dev->wait_us);
return readl(&dev->regs->drec);
}
static int send_byte(struct uniphier_i2c_dev *dev, u32 dtrm, bool *stop)
{
int ret = 0;
u32 drec;
drec = send_and_recv_byte(dev, dtrm);
if (drec & I2C_DREC_LAB) {
debug("uniphier_i2c: bus arbitration failed\n");
*stop = false;
ret = -EREMOTEIO;
}
if (drec & I2C_DREC_LRB) {
debug("uniphier_i2c: slave did not return ACK\n");
ret = -EREMOTEIO;
}
return ret;
}
static int uniphier_i2c_transmit(struct uniphier_i2c_dev *dev, uint addr,
uint len, const u8 *buf, bool *stop)
{
int ret;
debug("%s: addr = %x, len = %d\n", __func__, addr, len);
ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK | addr << 1, stop);
if (ret < 0)
goto fail;
while (len--) {
ret = send_byte(dev, I2C_DTRM_NACK | *buf++, stop);
if (ret < 0)
goto fail;
}
fail:
if (*stop)
writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
return ret;
}
static int uniphier_i2c_receive(struct uniphier_i2c_dev *dev, uint addr,
uint len, u8 *buf, bool *stop)
{
int ret;
debug("%s: addr = %x, len = %d\n", __func__, addr, len);
ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK |
I2C_DTRM_RD | addr << 1, stop);
if (ret < 0)
goto fail;
while (len--)
*buf++ = send_and_recv_byte(dev, len ? 0 : I2C_DTRM_NACK);
fail:
if (*stop)
writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
return ret;
}
static int uniphier_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
int nmsgs)
{
int ret = 0;
struct uniphier_i2c_dev *dev = dev_get_priv(bus);
bool stop;
for (; nmsgs > 0; nmsgs--, msg++) {
/* If next message is read, skip the stop condition */
stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
if (msg->flags & I2C_M_RD)
ret = uniphier_i2c_receive(dev, msg->addr, msg->len,
msg->buf, &stop);
else
ret = uniphier_i2c_transmit(dev, msg->addr, msg->len,
msg->buf, &stop);
if (ret < 0)
break;
}
return ret;
}
static int uniphier_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct uniphier_i2c_dev *priv = dev_get_priv(bus);
/* max supported frequency is 400 kHz */
if (speed > 400000)
return -EINVAL;
/* bus reset: make sure the bus is idle when change the frequency */
writel(0x1, &priv->regs->brst);
writel((priv->input_clk / speed / 2 << 16) | (priv->input_clk / speed),
&priv->regs->clk);
writel(0x3, &priv->regs->brst);
/*
* Theoretically, each byte can be transferred in
* 1000000 * 9 / speed usec. For safety, wait more than double.
*/
priv->wait_us = 20000000 / speed;
return 0;
}
static const struct dm_i2c_ops uniphier_i2c_ops = {
.xfer = uniphier_i2c_xfer,
.set_bus_speed = uniphier_i2c_set_bus_speed,
};
static const struct udevice_id uniphier_i2c_of_match[] = {
{ .compatible = "panasonic,uniphier-i2c" },
{},
};
U_BOOT_DRIVER(uniphier_i2c) = {
.name = "uniphier-i2c",
.id = UCLASS_I2C,
.of_match = uniphier_i2c_of_match,
.probe = uniphier_i2c_probe,
.remove = uniphier_i2c_remove,
.priv_auto_alloc_size = sizeof(struct uniphier_i2c_dev),
.ops = &uniphier_i2c_ops,
};

View File

@@ -9,8 +9,9 @@
* as they seem to have the same I2C controller inside.
* The different address mapping is handled by the s3c24xx.h files below.
*/
#include <common.h>
#include <errno.h>
#include <dm.h>
#include <fdtdec.h>
#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
#include <asm/arch/clk.h>
@@ -121,13 +122,23 @@
#define CONFIG_MAX_I2C_NUM 1
#endif
DECLARE_GLOBAL_DATA_PTR;
/*
* For SPL boot some boards need i2c before SDRAM is initialised so force
* variables to live in SRAM
*/
#ifdef CONFIG_SYS_I2C
static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM]
__attribute__((section(".data")));
#endif
enum exynos_i2c_type {
EXYNOS_I2C_STD,
EXYNOS_I2C_HS,
};
#ifdef CONFIG_SYS_I2C
/**
* Get a pointer to the given bus index
*
@@ -147,6 +158,7 @@ static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx)
debug("Undefined bus: %d\n", bus_idx);
return NULL;
}
#endif
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
static int GetI2CSDA(void)
@@ -251,6 +263,7 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c)
writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
}
#ifdef CONFIG_SYS_I2C
static struct s3c24x0_i2c *get_base_i2c(int bus)
{
#ifdef CONFIG_EXYNOS4
@@ -267,6 +280,7 @@ static struct s3c24x0_i2c *get_base_i2c(int bus)
return s3c24x0_get_base_i2c();
#endif
}
#endif
static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
{
@@ -326,7 +340,7 @@ static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus)
return 0;
}
}
return -1;
return -EINVAL;
}
static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus)
@@ -398,18 +412,20 @@ static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus)
hsi2c_ch_init(i2c_bus);
}
#ifdef CONFIG_SYS_I2C
static void s3c24x0_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
struct s3c24x0_i2c *i2c;
struct s3c24x0_i2c_bus *bus;
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
#endif
ulong start_time = get_timer(0);
/* By default i2c channel 0 is the current bus */
i2c = get_base_i2c(adap->hwadapnr);
bus = &i2c_bus[adap->hwadapnr];
if (!bus)
return;
/*
* In case the previous transfer is still going, wait to give it a
@@ -470,12 +486,13 @@ static void s3c24x0_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
#endif
}
#endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */
i2c_ch_init(i2c, speed, slaveadd);
bus = &i2c_bus[adap->hwadapnr];
bus->active = true;
bus->regs = i2c;
}
#endif /* CONFIG_SYS_I2C */
/*
* Poll the appropriate bit of the fifo status register until the interface is
@@ -698,20 +715,27 @@ static int hsi2c_read(struct exynos5_hsi2c *i2c,
return rv;
}
#ifdef CONFIG_SYS_I2C
static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap,
unsigned int speed)
unsigned int speed)
#else
static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
#endif
{
struct s3c24x0_i2c_bus *i2c_bus;
#ifdef CONFIG_SYS_I2C
i2c_bus = get_bus(adap->hwadapnr);
if (!i2c_bus)
return -1;
return -EFAULT;
#else
i2c_bus = dev_get_priv(dev);
#endif
i2c_bus->clock_frequency = speed;
if (i2c_bus->is_highspeed) {
if (hsi2c_get_clk_details(i2c_bus))
return -1;
return -EFAULT;
hsi2c_ch_init(i2c_bus);
} else {
i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
@@ -721,17 +745,6 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap,
return 0;
}
#ifdef CONFIG_EXYNOS5
static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
/* This will override the speed selected in the fdt for that port */
debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
if (i2c_set_bus_speed(speed))
printf("i2c_init: failed to init bus %d for speed = %d\n",
adap->hwadapnr, speed);
}
#endif
/*
* cmd_type is 0 for write, 1 for read.
*
@@ -844,15 +857,23 @@ bailout:
return result;
}
#ifdef CONFIG_SYS_I2C
static int s3c24x0_i2c_probe(struct i2c_adapter *adap, uchar chip)
#else
static int s3c24x0_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
#endif
{
struct s3c24x0_i2c_bus *i2c_bus;
uchar buf[1];
int ret;
#ifdef CONFIG_SYS_I2C
i2c_bus = get_bus(adap->hwadapnr);
if (!i2c_bus)
return -1;
return -EFAULT;
#else
i2c_bus = dev_get_priv(dev);
#endif
buf[0] = 0;
/*
@@ -871,6 +892,7 @@ static int s3c24x0_i2c_probe(struct i2c_adapter *adap, uchar chip)
return ret != I2C_OK;
}
#ifdef CONFIG_SYS_I2C
static int s3c24x0_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
int alen, uchar *buffer, int len)
{
@@ -878,9 +900,13 @@ static int s3c24x0_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
uchar xaddr[4];
int ret;
i2c_bus = get_bus(adap->hwadapnr);
if (!i2c_bus)
return -EFAULT;
if (alen > 4) {
debug("I2C read: addr len %d not supported\n", alen);
return 1;
return -EADDRNOTAVAIL;
}
if (alen > 0) {
@@ -906,10 +932,6 @@ static int s3c24x0_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
i2c_bus = get_bus(adap->hwadapnr);
if (!i2c_bus)
return -1;
if (i2c_bus->is_highspeed)
ret = hsi2c_read(i2c_bus->hsregs, chip, &xaddr[4 - alen],
alen, buffer, len);
@@ -921,7 +943,7 @@ static int s3c24x0_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
if (i2c_bus->is_highspeed)
exynos5_i2c_reset(i2c_bus);
debug("I2c read failed %d\n", ret);
return 1;
return -EIO;
}
return 0;
}
@@ -933,9 +955,13 @@ static int s3c24x0_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
uchar xaddr[4];
int ret;
i2c_bus = get_bus(adap->hwadapnr);
if (!i2c_bus)
return -EFAULT;
if (alen > 4) {
debug("I2C write: addr len %d not supported\n", alen);
return 1;
return -EINVAL;
}
if (alen > 0) {
@@ -960,10 +986,6 @@ static int s3c24x0_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
i2c_bus = get_bus(adap->hwadapnr);
if (!i2c_bus)
return -1;
if (i2c_bus->is_highspeed)
ret = hsi2c_write(i2c_bus->hsregs, chip, &xaddr[4 - alen],
alen, buffer, len, true);
@@ -985,7 +1007,7 @@ static void process_nodes(const void *blob, int node_list[], int count,
int is_highspeed)
{
struct s3c24x0_i2c_bus *bus;
int i;
int i, flags;
for (i = 0; i < count; i++) {
int node = node_list[i];
@@ -997,12 +1019,15 @@ static void process_nodes(const void *blob, int node_list[], int count,
bus->active = true;
bus->is_highspeed = is_highspeed;
if (is_highspeed)
if (is_highspeed) {
flags = PINMUX_FLAG_HS_MODE;
bus->hsregs = (struct exynos5_hsi2c *)
fdtdec_get_addr(blob, node, "reg");
else
} else {
flags = 0;
bus->regs = (struct s3c24x0_i2c *)
fdtdec_get_addr(blob, node, "reg");
}
bus->id = pinmux_decode_periph_id(blob, node);
bus->clock_frequency = fdtdec_get_int(blob, node,
@@ -1010,7 +1035,7 @@ static void process_nodes(const void *blob, int node_list[], int count,
CONFIG_SYS_I2C_S3C24X0_SPEED);
bus->node = node;
bus->bus_num = i;
exynos_pinmux_config(bus->id, 0);
exynos_pinmux_config(PERIPH_ID_I2C0 + bus->id, flags);
/* Mark position as used */
node_list[i] = -1;
@@ -1033,7 +1058,6 @@ void board_i2c_init(const void *blob)
COMPAT_SAMSUNG_EXYNOS5_I2C, node_list,
CONFIG_MAX_I2C_NUM);
process_nodes(blob, node_list, count, 1);
}
int i2c_get_bus_num_fdt(int node)
@@ -1046,7 +1070,7 @@ int i2c_get_bus_num_fdt(int node)
}
debug("%s: Can't find any matched I2C bus\n", __func__);
return -1;
return -EINVAL;
}
int i2c_reset_port_fdt(const void *blob, int node)
@@ -1057,18 +1081,18 @@ int i2c_reset_port_fdt(const void *blob, int node)
bus = i2c_get_bus_num_fdt(node);
if (bus < 0) {
debug("could not get bus for node %d\n", node);
return -1;
return bus;
}
i2c_bus = get_bus(bus);
if (!i2c_bus) {
debug("get_bus() failed for node node %d\n", node);
return -1;
debug("get_bus() failed for node %d\n", node);
return -EFAULT;
}
if (i2c_bus->is_highspeed) {
if (hsi2c_get_clk_details(i2c_bus))
return -1;
return -EINVAL;
hsi2c_ch_init(i2c_bus);
} else {
i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
@@ -1077,7 +1101,17 @@ int i2c_reset_port_fdt(const void *blob, int node)
return 0;
}
#endif
#endif /* CONFIG_OF_CONTROL */
#ifdef CONFIG_EXYNOS5
static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
/* This will override the speed selected in the fdt for that port */
debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
if (i2c_set_bus_speed(speed))
error("i2c_init: failed to init bus for speed = %d", speed);
}
#endif /* CONFIG_EXYNOS5 */
/*
* Register s3c24x0 i2c adapters
@@ -1247,3 +1281,120 @@ U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
#endif
#endif /* CONFIG_SYS_I2C */
#ifdef CONFIG_DM_I2C
static int i2c_write_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
uchar *buffer, int len, bool end_with_repeated_start)
{
int ret;
if (i2c_bus->is_highspeed) {
ret = hsi2c_write(i2c_bus->hsregs, chip, 0, 0,
buffer, len, true);
if (ret)
exynos5_i2c_reset(i2c_bus);
} else {
ret = i2c_transfer(i2c_bus->regs, I2C_WRITE,
chip << 1, 0, 0, buffer, len);
}
return ret != I2C_OK;
}
static int i2c_read_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
uchar *buffer, int len)
{
int ret;
if (i2c_bus->is_highspeed) {
ret = hsi2c_read(i2c_bus->hsregs, chip, 0, 0, buffer, len);
if (ret)
exynos5_i2c_reset(i2c_bus);
} else {
ret = i2c_transfer(i2c_bus->regs, I2C_READ,
chip << 1, 0, 0, buffer, len);
}
return ret != I2C_OK;
}
static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
int nmsgs)
{
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
int ret;
for (; nmsgs > 0; nmsgs--, msg++) {
bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
if (msg->flags & I2C_M_RD) {
ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
msg->len);
} else {
ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
msg->len, next_is_read);
}
if (ret)
return -EREMOTEIO;
}
return 0;
}
static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
{
const void *blob = gd->fdt_blob;
struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
int node, flags;
i2c_bus->is_highspeed = dev->of_id->data;
node = dev->of_offset;
if (i2c_bus->is_highspeed) {
flags = PINMUX_FLAG_HS_MODE;
i2c_bus->hsregs = (struct exynos5_hsi2c *)
fdtdec_get_addr(blob, node, "reg");
} else {
flags = 0;
i2c_bus->regs = (struct s3c24x0_i2c *)
fdtdec_get_addr(blob, node, "reg");
}
i2c_bus->id = pinmux_decode_periph_id(blob, node);
i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
"clock-frequency",
CONFIG_SYS_I2C_S3C24X0_SPEED);
i2c_bus->node = node;
i2c_bus->bus_num = dev->seq;
exynos_pinmux_config(i2c_bus->id, flags);
i2c_bus->active = true;
return 0;
}
static const struct dm_i2c_ops s3c_i2c_ops = {
.xfer = s3c24x0_i2c_xfer,
.probe_chip = s3c24x0_i2c_probe,
.set_bus_speed = s3c24x0_i2c_set_bus_speed,
};
static const struct udevice_id s3c_i2c_ids[] = {
{ .compatible = "samsung,s3c2440-i2c", .data = EXYNOS_I2C_STD },
{ .compatible = "samsung,exynos5-hsi2c", .data = EXYNOS_I2C_HS },
{ }
};
U_BOOT_DRIVER(i2c_s3c) = {
.name = "i2c_s3c",
.id = UCLASS_I2C,
.of_match = s3c_i2c_ids,
.ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
.ops = &s3c_i2c_ops,
};
#endif /* CONFIG_DM_I2C */

View File

@@ -25,24 +25,24 @@ struct dm_sandbox_i2c_emul_priv {
static int get_emul(struct udevice *dev, struct udevice **devp,
struct dm_i2c_ops **opsp)
{
struct dm_i2c_chip *priv;
struct dm_i2c_chip *plat;
int ret;
*devp = NULL;
*opsp = NULL;
priv = dev_get_parentdata(dev);
if (!priv->emul) {
plat = dev_get_parent_platdata(dev);
if (!plat->emul) {
ret = dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset,
false);
if (ret)
return ret;
ret = device_get_child(dev, 0, &priv->emul);
ret = device_get_child(dev, 0, &plat->emul);
if (ret)
return ret;
}
*devp = priv->emul;
*opsp = i2c_get_ops(priv->emul);
*devp = plat->emul;
*opsp = i2c_get_ops(plat->emul);
return 0;
}
@@ -60,7 +60,7 @@ static int sandbox_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
if (msg->addr == SANDBOX_I2C_TEST_ADDR)
return 0;
ret = i2c_get_chip(bus, msg->addr, &dev);
ret = i2c_get_chip(bus, msg->addr, 1, &dev);
if (ret)
return ret;
@@ -82,20 +82,6 @@ static const struct dm_i2c_ops sandbox_i2c_ops = {
.xfer = sandbox_i2c_xfer,
};
static int sandbox_i2c_child_pre_probe(struct udevice *dev)
{
struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
/* Ignore our test address */
if (i2c_chip->chip_addr == SANDBOX_I2C_TEST_ADDR)
return 0;
if (dev->of_offset == -1)
return 0;
return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
i2c_chip);
}
static const struct udevice_id sandbox_i2c_ids[] = {
{ .compatible = "sandbox,i2c" },
{ }
@@ -105,7 +91,5 @@ U_BOOT_DRIVER(i2c_sandbox) = {
.name = "i2c_sandbox",
.id = UCLASS_I2C,
.of_match = sandbox_i2c_ids,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.child_pre_probe = sandbox_i2c_child_pre_probe,
.ops = &sandbox_i2c_ops,
};

View File

@@ -484,21 +484,6 @@ static const struct dm_i2c_ops tegra_i2c_ops = {
.set_bus_speed = tegra_i2c_set_bus_speed,
};
static int tegra_i2c_child_pre_probe(struct udevice *dev)
{
struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
if (dev->of_offset == -1)
return 0;
return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
i2c_chip);
}
static int tegra_i2c_ofdata_to_platdata(struct udevice *dev)
{
return 0;
}
static const struct udevice_id tegra_i2c_ids[] = {
{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
{ .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
@@ -510,10 +495,7 @@ U_BOOT_DRIVER(i2c_tegra) = {
.name = "i2c_tegra",
.id = UCLASS_I2C,
.of_match = tegra_i2c_ids,
.ofdata_to_platdata = tegra_i2c_ofdata_to_platdata,
.probe = tegra_i2c_probe,
.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
.child_pre_probe = tegra_i2c_child_pre_probe,
.priv_auto_alloc_size = sizeof(struct i2c_bus),
.ops = &tegra_i2c_ops,
};

View File

@@ -154,7 +154,9 @@ static int prepare_proto3_response_buffer(struct cros_ec_dev *dev, int din_len)
* @param dev CROS-EC device
* @param dinp Returns pointer to response data
* @param din_len Maximum size of response in bytes
* @return number of bytes of response data, or <0 if error
* @return number of bytes of response data, or <0 if error. Note that error
* codes can be from errno.h or -ve EC_RES_INVALID_CHECKSUM values (and they
* overlap!)
*/
static int handle_proto3_response(struct cros_ec_dev *dev,
uint8_t **dinp, int din_len)
@@ -228,7 +230,7 @@ static int send_command_proto3(struct cros_ec_dev *dev,
#ifdef CONFIG_DM_CROS_EC
ops = dm_cros_ec_get_ops(dev->dev);
rv = ops->packet(dev->dev, out_bytes, in_bytes);
rv = ops->packet ? ops->packet(dev->dev, out_bytes, in_bytes) : -ENOSYS;
#else
switch (dev->interface) {
#ifdef CONFIG_CROS_EC_SPI
@@ -320,7 +322,7 @@ static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
* If not NULL, it will be updated to point to the data
* and will always be double word aligned (64-bits)
* @param din_len Maximum size of response in bytes
* @return number of bytes in response, or -1 on error
* @return number of bytes in response, or -ve on error
*/
static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
int cmd_version, const void *dout, int dout_len, uint8_t **dinp,
@@ -387,7 +389,7 @@ static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
* It not NULL, it is a place for ec_command() to copy the
* data to.
* @param din_len Maximum size of response in bytes
* @return number of bytes in response, or -1 on error
* @return number of bytes in response, or -ve on error
*/
static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
const void *dout, int dout_len,
@@ -606,10 +608,10 @@ int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd,
int cros_ec_interrupt_pending(struct cros_ec_dev *dev)
{
/* no interrupt support : always poll */
if (!fdt_gpio_isvalid(&dev->ec_int))
if (!dm_gpio_is_valid(&dev->ec_int))
return -ENOENT;
return !gpio_get_value(dev->ec_int.gpio);
return dm_gpio_get_value(&dev->ec_int);
}
int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_mkbp_info *info)
@@ -1072,7 +1074,8 @@ static int cros_ec_decode_fdt(const void *blob, int node,
return -1;
}
fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int);
gpio_request_by_name_nodev(blob, node, "ec-interrupt", 0, &dev->ec_int,
GPIOD_IS_IN);
dev->optimise_flash_write = fdtdec_get_bool(blob, node,
"optimise-flash-write");
*devp = dev;
@@ -1090,17 +1093,11 @@ int cros_ec_register(struct udevice *dev)
char id[MSG_BYTES];
cdev->dev = dev;
fdtdec_decode_gpio(blob, node, "ec-interrupt", &cdev->ec_int);
gpio_request_by_name(dev, "ec-interrupt", 0, &cdev->ec_int,
GPIOD_IS_IN);
cdev->optimise_flash_write = fdtdec_get_bool(blob, node,
"optimise-flash-write");
/* we will poll the EC interrupt line */
fdtdec_setup_gpio(&cdev->ec_int);
if (fdt_gpio_isvalid(&cdev->ec_int)) {
gpio_request(cdev->ec_int.gpio, "cros-ec-irq");
gpio_direction_input(cdev->ec_int.gpio);
}
if (cros_ec_check_version(cdev)) {
debug("%s: Could not detect CROS-EC version\n", __func__);
return -CROS_EC_ERR_CHECK_VERSION;
@@ -1184,13 +1181,6 @@ int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp)
}
#endif
/* we will poll the EC interrupt line */
fdtdec_setup_gpio(&dev->ec_int);
if (fdt_gpio_isvalid(&dev->ec_int)) {
gpio_request(dev->ec_int.gpio, "cros-ec-irq");
gpio_direction_input(dev->ec_int.gpio);
}
if (cros_ec_check_version(dev)) {
debug("%s: Could not detect CROS-EC version\n", __func__);
return -CROS_EC_ERR_CHECK_VERSION;

View File

@@ -14,6 +14,7 @@
*/
#include <common.h>
#include <dm.h>
#include <i2c.h>
#include <cros_ec.h>
@@ -23,11 +24,11 @@
#define debug_trace(fmt, b...)
#endif
int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
const uint8_t *dout, int dout_len,
uint8_t **dinp, int din_len)
static int cros_ec_i2c_command(struct udevice *udev, uint8_t cmd,
int cmd_version, const uint8_t *dout,
int dout_len, uint8_t **dinp, int din_len)
{
int old_bus = 0;
struct cros_ec_dev *dev = udev->uclass_priv;
/* version8, cmd8, arglen8, out8[dout_len], csum8 */
int out_bytes = dout_len + 4;
/* response8, arglen8, in8[din_len], checksum8 */
@@ -37,8 +38,6 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
uint8_t *in_ptr;
int len, csum, ret;
old_bus = i2c_get_bus_num();
/*
* Sanity-check I/O sizes given transaction overhead in internal
* buffers.
@@ -86,36 +85,24 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
*ptr++ = (uint8_t)
cros_ec_calc_checksum(dev->dout, dout_len + 3);
/* Set to the proper i2c bus */
if (i2c_set_bus_num(dev->bus_num)) {
debug("%s: Cannot change to I2C bus %d\n", __func__,
dev->bus_num);
return -1;
}
/* Send output data */
cros_ec_dump_data("out", -1, dev->dout, out_bytes);
ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes);
ret = dm_i2c_write(udev, 0, dev->dout, out_bytes);
if (ret) {
debug("%s: Cannot complete I2C write to 0x%x\n",
__func__, dev->addr);
debug("%s: Cannot complete I2C write to %s\n", __func__,
udev->name);
ret = -1;
}
if (!ret) {
ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes);
ret = dm_i2c_read(udev, 0, in_ptr, in_bytes);
if (ret) {
debug("%s: Cannot complete I2C read from 0x%x\n",
__func__, dev->addr);
debug("%s: Cannot complete I2C read from %s\n",
__func__, udev->name);
ret = -1;
}
}
/* Return to original bus number */
i2c_set_bus_num(old_bus);
if (ret)
return ret;
if (*in_ptr != EC_RES_SUCCESS) {
debug("%s: Received bad result code %d\n", __func__, *in_ptr);
return -(int)*in_ptr;
@@ -142,35 +129,24 @@ int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
return din_len;
}
int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob)
static int cros_ec_probe(struct udevice *dev)
{
/* Decode interface-specific FDT params */
dev->max_frequency = fdtdec_get_int(blob, dev->node,
"i2c-max-frequency", 100000);
dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node);
if (dev->bus_num == -1) {
debug("%s: Failed to read bus number\n", __func__);
return -1;
}
dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1);
if (dev->addr == -1) {
debug("%s: Failed to read device address\n", __func__);
return -1;
}
return 0;
return cros_ec_register(dev);
}
/**
* Initialize I2C protocol.
*
* @param dev CROS_EC device
* @param blob Device tree blob
* @return 0 if ok, -1 on error
*/
int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob)
{
i2c_init(dev->max_frequency, dev->addr);
static struct dm_cros_ec_ops cros_ec_ops = {
.command = cros_ec_i2c_command,
};
return 0;
}
static const struct udevice_id cros_ec_ids[] = {
{ .compatible = "google,cros-ec" },
{ }
};
U_BOOT_DRIVER(cros_ec_i2c) = {
.name = "cros_ec",
.id = UCLASS_CROS_EC,
.of_match = cros_ec_ids,
.probe = cros_ec_probe,
.ops = &cros_ec_ops,
};

View File

@@ -21,14 +21,9 @@
DECLARE_GLOBAL_DATA_PTR;
#ifdef CONFIG_DM_CROS_EC
int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
{
struct cros_ec_dev *dev = udev->uclass_priv;
#else
int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
{
#endif
struct spi_slave *slave = dev_get_parentdata(dev->dev);
int rv;
@@ -67,18 +62,11 @@ int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
* @param din_len Maximum size of response in bytes
* @return number of bytes in response, or -1 on error
*/
#ifdef CONFIG_DM_CROS_EC
int cros_ec_spi_command(struct udevice *udev, uint8_t cmd, int cmd_version,
const uint8_t *dout, int dout_len,
uint8_t **dinp, int din_len)
{
struct cros_ec_dev *dev = udev->uclass_priv;
#else
int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
const uint8_t *dout, int dout_len,
uint8_t **dinp, int din_len)
{
#endif
struct spi_slave *slave = dev_get_parentdata(dev->dev);
int in_bytes = din_len + 4; /* status, length, checksum, trailer */
uint8_t *out;
@@ -166,65 +154,12 @@ int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
return len;
}
#ifndef CONFIG_DM_CROS_EC
int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
static int cros_ec_probe(struct udevice *dev)
{
/* Decode interface-specific FDT params */
dev->max_frequency = fdtdec_get_int(blob, dev->node,
"spi-max-frequency", 500000);
dev->cs = fdtdec_get_int(blob, dev->node, "reg", 0);
return 0;
}
/**
* Initialize SPI protocol.
*
* @param dev CROS_EC device
* @param blob Device tree blob
* @return 0 if ok, -1 on error
*/
int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)
{
int ret;
ret = spi_setup_slave_fdt(blob, dev->node, dev->parent_node,
&slave);
if (ret) {
debug("%s: Could not setup SPI slave\n", __func__);
return ret;
}
return 0;
}
#endif
#ifdef CONFIG_DM_CROS_EC
int cros_ec_probe(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parentdata(dev);
int ret;
/*
* TODO(sjg@chromium.org)
*
* This is really horrible at present. It is an artifact of removing
* the child_pre_probe() method for SPI. Everything here could go in
* an automatic function, except that spi_get_bus_and_cs() wants to
* set it up manually and call device_probe_child().
*
* The solution may be to re-enable the child_pre_probe() method for
* SPI and have it do nothing if the child is already passed in via
* device_probe_child().
*/
slave->dev = dev;
ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
if (ret)
return ret;
return cros_ec_register(dev);
}
struct dm_cros_ec_ops cros_ec_ops = {
static struct dm_cros_ec_ops cros_ec_ops = {
.packet = cros_ec_spi_packet,
.command = cros_ec_spi_command,
};
@@ -241,4 +176,3 @@ U_BOOT_DRIVER(cros_ec_spi) = {
.probe = cros_ec_probe,
.ops = &cros_ec_ops,
};
#endif

View File

@@ -102,17 +102,14 @@ struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS];
static int do_sdhci_init(struct sdhci_host *host)
{
char str[20];
int dev_id, flag;
int err = 0;
flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
dev_id = host->index + PERIPH_ID_SDMMC0;
if (fdt_gpio_isvalid(&host->pwr_gpio)) {
sprintf(str, "sdhci%d_power", host->index & 0xf);
gpio_request(host->pwr_gpio.gpio, str);
gpio_direction_output(host->pwr_gpio.gpio, 1);
if (dm_gpio_is_valid(&host->pwr_gpio)) {
dm_gpio_set_value(&host->pwr_gpio, 1);
err = exynos_pinmux_config(dev_id, flag);
if (err) {
debug("MMC not configured\n");
@@ -120,11 +117,8 @@ static int do_sdhci_init(struct sdhci_host *host)
}
}
if (fdt_gpio_isvalid(&host->cd_gpio)) {
sprintf(str, "sdhci%d_cd", host->index & 0xf);
gpio_request(host->cd_gpio.gpio, str);
gpio_direction_input(host->cd_gpio.gpio);
if (gpio_get_value(host->cd_gpio.gpio))
if (dm_gpio_is_valid(&host->cd_gpio)) {
if (dm_gpio_get_value(&host->cd_gpio))
return -ENODEV;
err = exynos_pinmux_config(dev_id, flag);
@@ -166,8 +160,10 @@ static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host)
}
host->ioaddr = (void *)base;
fdtdec_decode_gpio(blob, node, "pwr-gpios", &host->pwr_gpio);
fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
gpio_request_by_name_nodev(blob, node, "pwr-gpios", 0, &host->pwr_gpio,
GPIOD_IS_OUT);
gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio,
GPIOD_IS_IN);
return 0;
}

View File

@@ -515,8 +515,8 @@ static int tegra_mmc_getcd(struct mmc *mmc)
debug("tegra_mmc_getcd called\n");
if (fdt_gpio_isvalid(&host->cd_gpio))
return fdtdec_get_gpio(&host->cd_gpio);
if (dm_gpio_is_valid(&host->cd_gpio))
return dm_gpio_get_value(&host->cd_gpio);
return 1;
}
@@ -531,7 +531,6 @@ static const struct mmc_ops tegra_mmc_ops = {
static int do_mmc_init(int dev_index)
{
struct mmc_host *host;
char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */
struct mmc *mmc;
/* DT should have been read & host config filled in */
@@ -539,27 +538,15 @@ static int do_mmc_init(int dev_index)
if (!host->enabled)
return -1;
debug(" do_mmc_init: index %d, bus width %d "
"pwr_gpio %d cd_gpio %d\n",
dev_index, host->width,
host->pwr_gpio.gpio, host->cd_gpio.gpio);
debug(" do_mmc_init: index %d, bus width %d pwr_gpio %d cd_gpio %d\n",
dev_index, host->width, gpio_get_number(&host->pwr_gpio),
gpio_get_number(&host->cd_gpio));
host->clock = 0;
clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000);
if (fdt_gpio_isvalid(&host->pwr_gpio)) {
sprintf(gpusage, "SD/MMC%d PWR", dev_index);
gpio_request(host->pwr_gpio.gpio, gpusage);
gpio_direction_output(host->pwr_gpio.gpio, 1);
debug(" Power GPIO name = %s\n", host->pwr_gpio.name);
}
if (fdt_gpio_isvalid(&host->cd_gpio)) {
sprintf(gpusage, "SD/MMC%d CD", dev_index);
gpio_request(host->cd_gpio.gpio, gpusage);
gpio_direction_input(host->cd_gpio.gpio);
debug(" CD GPIO name = %s\n", host->cd_gpio.name);
}
if (dm_gpio_is_valid(&host->pwr_gpio))
dm_gpio_set_value(&host->pwr_gpio, 1);
memset(&host->cfg, 0, sizeof(host->cfg));
@@ -626,9 +613,12 @@ static int mmc_get_config(const void *blob, int node, struct mmc_host *host)
debug("%s: no sdmmc width found\n", __func__);
/* These GPIOs are optional */
fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
fdtdec_decode_gpio(blob, node, "wp-gpios", &host->wp_gpio);
fdtdec_decode_gpio(blob, node, "power-gpios", &host->pwr_gpio);
gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio,
GPIOD_IS_IN);
gpio_request_by_name_nodev(blob, node, "wp-gpios", 0, &host->wp_gpio,
GPIOD_IS_IN);
gpio_request_by_name_nodev(blob, node, "power-gpios", 0,
&host->pwr_gpio, GPIOD_IS_OUT);
debug("%s: found controller at %p, width = %d, periph_id = %d\n",
__func__, host->reg, host->width, host->mmc_id);

View File

@@ -79,7 +79,7 @@ enum {
struct fdt_nand {
struct nand_ctlr *reg;
int enabled; /* 1 to enable, 0 to disable */
struct fdt_gpio_state wp_gpio; /* write-protect GPIO */
struct gpio_desc wp_gpio; /* write-protect GPIO */
s32 width; /* bit width, normally 8 */
u32 timing[FDT_NAND_TIMING_COUNT];
};
@@ -945,8 +945,8 @@ static int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config)
config->reg = (struct nand_ctlr *)fdtdec_get_addr(blob, node, "reg");
config->enabled = fdtdec_get_is_enabled(blob, node);
config->width = fdtdec_get_int(blob, node, "nvidia,nand-width", 8);
err = fdtdec_decode_gpio(blob, node, "nvidia,wp-gpios",
&config->wp_gpio);
err = gpio_request_by_name_nodev(blob, node, "nvidia,wp-gpios", 0,
&config->wp_gpio, GPIOD_IS_OUT);
if (err)
return err;
err = fdtdec_get_int_array(blob, node, "nvidia,timing",
@@ -1009,8 +1009,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum)
/* Adjust timing for NAND device */
setup_timing(config->timing, info->reg);
fdtdec_setup_gpio(&config->wp_gpio);
gpio_direction_output(config->wp_gpio.gpio, 1);
dm_gpio_set_value(&config->wp_gpio, 1);
our_mtd = &nand_info[devnum];
our_mtd->priv = nand;

View File

@@ -141,8 +141,10 @@ static int sandbox_sf_probe(struct udevice *dev)
assert(bus->seq != -1);
if (bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS)
spec = state->spi[bus->seq][cs].spec;
if (!spec)
return -ENOENT;
if (!spec) {
ret = -ENOENT;
goto error;
}
file = strchr(spec, ':');
if (!file) {
@@ -196,6 +198,7 @@ static int sandbox_sf_probe(struct udevice *dev)
return 0;
error:
debug("%s: Got error %d\n", __func__, ret);
return ret;
}
@@ -587,6 +590,11 @@ int sandbox_sf_bind_emul(struct sandbox_state *state, int busnum, int cs,
void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs)
{
struct udevice *dev;
dev = state->spi[busnum][cs].emul;
device_remove(dev);
device_unbind(dev);
state->spi[busnum][cs].emul = NULL;
}

View File

@@ -481,11 +481,12 @@ int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len)
int spi_flash_std_probe(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parentdata(dev);
struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
struct spi_flash *flash;
flash = dev->uclass_priv;
flash->dev = dev;
debug("%s: slave=%p, cs=%d\n", __func__, slave, slave->cs);
debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs);
return spi_flash_probe_slave(slave, flash);
}

View File

@@ -31,7 +31,7 @@ static int as3722_read(struct udevice *pmic, u8 reg, u8 *value)
{
int err;
err = i2c_read(pmic, reg, value, 1);
err = dm_i2c_read(pmic, reg, value, 1);
if (err < 0)
return err;
@@ -42,7 +42,7 @@ static int as3722_write(struct udevice *pmic, u8 reg, u8 value)
{
int err;
err = i2c_write(pmic, reg, &value, 1);
err = dm_i2c_write(pmic, reg, &value, 1);
if (err < 0)
return err;
@@ -242,7 +242,7 @@ int as3722_init(struct udevice **devp)
const unsigned int address = 0x40;
int err;
err = i2c_get_chip_for_busnum(bus, address, &pmic);
err = i2c_get_chip_for_busnum(bus, address, 1, &pmic);
if (err)
return err;
err = as3722_read_id(pmic, &id, &revision);

View File

@@ -37,7 +37,7 @@ static int tps6586x_read(int reg)
int retval = -1;
for (i = 0; i < MAX_I2C_RETRY; ++i) {
if (!i2c_read(tps6586x_dev, reg, &data, 1)) {
if (!dm_i2c_read(tps6586x_dev, reg, &data, 1)) {
retval = (int)data;
goto exit;
}
@@ -60,7 +60,7 @@ static int tps6586x_write(int reg, uchar *data, uint len)
int retval = -1;
for (i = 0; i < MAX_I2C_RETRY; ++i) {
if (!i2c_write(tps6586x_dev, reg, data, len)) {
if (!dm_i2c_write(tps6586x_dev, reg, data, len)) {
retval = 0;
goto exit;
}

View File

@@ -297,6 +297,7 @@ static int serial_pre_remove(struct udevice *dev)
UCLASS_DRIVER(serial) = {
.id = UCLASS_SERIAL,
.name = "serial",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_probe = serial_post_probe,
.pre_remove = serial_pre_remove,
.per_device_auto_alloc_size = sizeof(struct serial_dev_priv),

View File

@@ -340,6 +340,5 @@ U_BOOT_DRIVER(cadence_spi) = {
.ofdata_to_platdata = cadence_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct cadence_spi_platdata),
.priv_auto_alloc_size = sizeof(struct cadence_spi_priv),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = cadence_spi_probe,
};

View File

@@ -421,6 +421,5 @@ U_BOOT_DRIVER(dw_spi) = {
.ofdata_to_platdata = dw_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct dw_spi_platdata),
.priv_auto_alloc_size = sizeof(struct dw_spi_priv),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = dw_spi_probe,
};

View File

@@ -425,6 +425,5 @@ U_BOOT_DRIVER(exynos_spi) = {
.ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
.priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = exynos_spi_probe,
};

View File

@@ -160,6 +160,5 @@ U_BOOT_DRIVER(spi_sandbox) = {
.name = "spi_sandbox",
.id = UCLASS_SPI,
.of_match = sandbox_spi_ids,
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.ops = &sandbox_spi_ops,
};

View File

@@ -21,10 +21,10 @@
DECLARE_GLOBAL_DATA_PTR;
struct soft_spi_platdata {
struct fdt_gpio_state cs;
struct fdt_gpio_state sclk;
struct fdt_gpio_state mosi;
struct fdt_gpio_state miso;
struct gpio_desc cs;
struct gpio_desc sclk;
struct gpio_desc mosi;
struct gpio_desc miso;
int spi_delay_us;
};
@@ -35,9 +35,8 @@ struct soft_spi_priv {
static int soft_spi_scl(struct udevice *dev, int bit)
{
struct soft_spi_platdata *plat = dev->platdata;
struct soft_spi_priv *priv = dev_get_priv(dev);
gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL ? bit : !bit);
dm_gpio_set_value(&plat->sclk, bit);
return 0;
}
@@ -46,7 +45,7 @@ static int soft_spi_sda(struct udevice *dev, int bit)
{
struct soft_spi_platdata *plat = dev->platdata;
gpio_set_value(plat->mosi.gpio, bit);
dm_gpio_set_value(&plat->mosi, bit);
return 0;
}
@@ -54,11 +53,10 @@ static int soft_spi_sda(struct udevice *dev, int bit)
static int soft_spi_cs_activate(struct udevice *dev)
{
struct soft_spi_platdata *plat = dev->platdata;
struct soft_spi_priv *priv = dev_get_priv(dev);
gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL);
gpio_set_value(plat->cs.gpio, priv->mode & SPI_CS_HIGH);
dm_gpio_set_value(&plat->cs, 0);
dm_gpio_set_value(&plat->sclk, 0);
dm_gpio_set_value(&plat->cs, 1);
return 0;
}
@@ -66,9 +64,8 @@ static int soft_spi_cs_activate(struct udevice *dev)
static int soft_spi_cs_deactivate(struct udevice *dev)
{
struct soft_spi_platdata *plat = dev->platdata;
struct soft_spi_priv *priv = dev_get_priv(dev);
gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
dm_gpio_set_value(&plat->cs, 0);
return 0;
}
@@ -109,7 +106,6 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
uchar tmpdout = 0;
const u8 *txd = dout;
u8 *rxd = din;
int cpol = priv->mode & SPI_CPOL;
int cpha = priv->mode & SPI_CPHA;
unsigned int j;
@@ -137,19 +133,19 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
}
if (!cpha)
soft_spi_scl(dev, !cpol);
soft_spi_scl(dev, 0);
soft_spi_sda(dev, tmpdout & 0x80);
udelay(plat->spi_delay_us);
if (cpha)
soft_spi_scl(dev, !cpol);
soft_spi_scl(dev, 0);
else
soft_spi_scl(dev, cpol);
soft_spi_scl(dev, 1);
tmpdin <<= 1;
tmpdin |= gpio_get_value(plat->miso.gpio);
tmpdin |= dm_gpio_get_value(&plat->miso);
tmpdout <<= 1;
udelay(plat->spi_delay_us);
if (cpha)
soft_spi_scl(dev, cpol);
soft_spi_scl(dev, 1);
}
/*
* If the number of bits isn't a multiple of 8, shift the last
@@ -183,14 +179,6 @@ static int soft_spi_set_mode(struct udevice *dev, unsigned int mode)
return 0;
}
static int soft_spi_child_pre_probe(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parentdata(dev);
slave->dev = dev;
return spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
}
static const struct dm_spi_ops soft_spi_ops = {
.claim_bus = soft_spi_claim_bus,
.release_bus = soft_spi_release_bus,
@@ -205,11 +193,6 @@ static int soft_spi_ofdata_to_platdata(struct udevice *dev)
const void *blob = gd->fdt_blob;
int node = dev->of_offset;
if (fdtdec_decode_gpio(blob, node, "cs-gpio", &plat->cs) ||
fdtdec_decode_gpio(blob, node, "sclk-gpio", &plat->sclk) ||
fdtdec_decode_gpio(blob, node, "mosi-gpio", &plat->mosi) ||
fdtdec_decode_gpio(blob, node, "miso-gpio", &plat->miso))
return -EINVAL;
plat->spi_delay_us = fdtdec_get_int(blob, node, "spi-delay-us", 0);
return 0;
@@ -219,16 +202,19 @@ static int soft_spi_probe(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parentdata(dev);
struct soft_spi_platdata *plat = dev->platdata;
int cs_flags, clk_flags;
gpio_request(plat->cs.gpio, "soft_spi_cs");
gpio_request(plat->sclk.gpio, "soft_spi_sclk");
gpio_request(plat->mosi.gpio, "soft_spi_mosi");
gpio_request(plat->miso.gpio, "soft_spi_miso");
gpio_direction_output(plat->sclk.gpio, slave->mode & SPI_CPOL);
gpio_direction_output(plat->mosi.gpio, 1);
gpio_direction_input(plat->miso.gpio);
gpio_direction_output(plat->cs.gpio, !(slave->mode & SPI_CS_HIGH));
cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW;
clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0;
if (gpio_request_by_name(dev, "cs-gpio", 0, &plat->cs,
GPIOD_IS_OUT | cs_flags) ||
gpio_request_by_name(dev, "sclk-gpio", 0, &plat->sclk,
GPIOD_IS_OUT | clk_flags) ||
gpio_request_by_name(dev, "mosi-gpio", 0, &plat->mosi,
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE) ||
gpio_request_by_name(dev, "miso-gpio", 0, &plat->miso,
GPIOD_IS_IN))
return -EINVAL;
return 0;
}
@@ -246,7 +232,5 @@ U_BOOT_DRIVER(soft_spi) = {
.ofdata_to_platdata = soft_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct soft_spi_platdata),
.priv_auto_alloc_size = sizeof(struct soft_spi_priv),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = soft_spi_probe,
.child_pre_probe = soft_spi_child_pre_probe,
};

View File

@@ -98,21 +98,51 @@ int spi_post_bind(struct udevice *dev)
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
int spi_post_probe(struct udevice *dev)
int spi_child_post_bind(struct udevice *dev)
{
struct dm_spi_bus *spi = dev->uclass_priv;
struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
spi->max_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
if (dev->of_offset == -1)
return 0;
return spi_slave_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
}
int spi_post_probe(struct udevice *bus)
{
struct dm_spi_bus *spi = bus->uclass_priv;
spi->max_hz = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
"spi-max-frequency", 0);
return 0;
}
int spi_child_pre_probe(struct udevice *dev)
{
struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
struct spi_slave *slave = dev_get_parentdata(dev);
/*
* This is needed because we pass struct spi_slave around the place
* instead slave->dev (a struct udevice). So we have to have some
* way to access the slave udevice given struct spi_slave. Once we
* change the SPI API to use udevice instead of spi_slave, we can
* drop this.
*/
slave->dev = dev;
slave->max_hz = plat->max_hz;
slave->mode = plat->mode;
return 0;
}
int spi_chip_select(struct udevice *dev)
{
struct spi_slave *slave = dev_get_parentdata(dev);
struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
return slave ? slave->cs : -ENOENT;
return plat ? plat->cs : -ENOENT;
}
int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
@@ -121,17 +151,11 @@ int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
for (device_find_first_child(bus, &dev); dev;
device_find_next_child(&dev)) {
struct spi_slave store;
struct spi_slave *slave = dev_get_parentdata(dev);
struct dm_spi_slave_platdata *plat;
if (!slave) {
slave = &store;
spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
slave);
}
debug("%s: slave=%p, cs=%d\n", __func__, slave,
slave ? slave->cs : -1);
if (slave && slave->cs == cs) {
plat = dev_get_parent_platdata(dev);
debug("%s: plat=%p, cs=%d\n", __func__, plat, plat->cs);
if (plat->cs == cs) {
*devp = dev;
return 0;
}
@@ -215,7 +239,6 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
struct udevice **busp, struct spi_slave **devp)
{
struct udevice *bus, *dev;
struct spi_slave *slave;
bool created = false;
int ret;
@@ -232,11 +255,17 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
* SPI flash chip - we will bind to the correct driver.
*/
if (ret == -ENODEV && drv_name) {
struct dm_spi_slave_platdata *plat;
debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
__func__, dev_name, busnum, cs, drv_name);
ret = device_bind_driver(bus, drv_name, dev_name, &dev);
if (ret)
return ret;
plat = dev_get_parent_platdata(dev);
plat->cs = cs;
plat->max_hz = speed;
plat->mode = mode;
created = true;
} else if (ret) {
printf("Invalid chip select %d:%d (err=%d)\n", busnum, cs,
@@ -245,23 +274,13 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
}
if (!device_active(dev)) {
slave = (struct spi_slave *)calloc(1,
sizeof(struct spi_slave));
if (!slave) {
ret = -ENOMEM;
goto err;
}
struct spi_slave *slave;
ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
slave);
ret = device_probe(dev);
if (ret)
goto err;
slave->cs = cs;
slave = dev_get_parentdata(dev);
slave->dev = dev;
ret = device_probe_child(dev, slave);
free(slave);
if (ret)
goto err;
}
ret = spi_set_speed_mode(bus, speed, mode);
@@ -275,6 +294,8 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
return 0;
err:
debug("%s: Error path, credted=%d, device '%s'\n", __func__,
created, dev->name);
if (created) {
device_remove(dev);
device_unbind(dev);
@@ -321,13 +342,13 @@ void spi_free_slave(struct spi_slave *slave)
slave->dev = NULL;
}
int spi_ofdata_to_platdata(const void *blob, int node,
struct spi_slave *spi)
int spi_slave_ofdata_to_platdata(const void *blob, int node,
struct dm_spi_slave_platdata *plat)
{
int mode = 0;
spi->cs = fdtdec_get_int(blob, node, "reg", -1);
spi->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0);
plat->cs = fdtdec_get_int(blob, node, "reg", -1);
plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0);
if (fdtdec_get_bool(blob, node, "spi-cpol"))
mode |= SPI_CPOL;
if (fdtdec_get_bool(blob, node, "spi-cpha"))
@@ -336,7 +357,7 @@ int spi_ofdata_to_platdata(const void *blob, int node,
mode |= SPI_CS_HIGH;
if (fdtdec_get_bool(blob, node, "spi-half-duplex"))
mode |= SPI_PREAMBLE;
spi->mode = mode;
plat->mode = mode;
return 0;
}
@@ -344,9 +365,15 @@ int spi_ofdata_to_platdata(const void *blob, int node,
UCLASS_DRIVER(spi) = {
.id = UCLASS_SPI,
.name = "spi",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.post_bind = spi_post_bind,
.post_probe = spi_post_probe,
.child_pre_probe = spi_child_pre_probe,
.per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.per_child_platdata_auto_alloc_size =
sizeof(struct dm_spi_slave_platdata),
.child_post_bind = spi_child_post_bind,
};
UCLASS_DRIVER(spi_generic) = {

View File

@@ -407,6 +407,5 @@ U_BOOT_DRIVER(tegra114_spi) = {
.ofdata_to_platdata = tegra114_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
.priv_auto_alloc_size = sizeof(struct tegra114_spi_priv),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = tegra114_spi_probe,
};

View File

@@ -348,6 +348,5 @@ U_BOOT_DRIVER(tegra20_sflash) = {
.ofdata_to_platdata = tegra20_sflash_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
.priv_auto_alloc_size = sizeof(struct tegra20_sflash_priv),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = tegra20_sflash_probe,
};

View File

@@ -361,6 +361,5 @@ U_BOOT_DRIVER(tegra30_spi) = {
.ofdata_to_platdata = tegra30_spi_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
.priv_auto_alloc_size = sizeof(struct tegra30_spi_priv),
.per_child_auto_alloc_size = sizeof(struct spi_slave),
.probe = tegra30_spi_probe,
};

View File

@@ -31,7 +31,7 @@ DECLARE_GLOBAL_DATA_PTR;
struct exynos_ehci {
struct exynos_usb_phy *usb;
struct ehci_hccr *hcd;
struct fdt_gpio_state vbus_gpio;
struct gpio_desc vbus_gpio;
};
static struct exynos_ehci exynos;
@@ -61,7 +61,8 @@ static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos)
exynos->hcd = (struct ehci_hccr *)addr;
/* Vbus gpio */
fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
&exynos->vbus_gpio, GPIOD_IS_OUT);
depth = 0;
node = fdtdec_next_compatible_subnode(blob, node,
@@ -236,9 +237,8 @@ int ehci_hcd_init(int index, enum usb_init_type init,
#ifdef CONFIG_OF_CONTROL
/* setup the Vbus gpio here */
if (fdt_gpio_isvalid(&ctx->vbus_gpio) &&
!fdtdec_setup_gpio(&ctx->vbus_gpio))
gpio_direction_output(ctx->vbus_gpio.gpio, 1);
if (dm_gpio_is_valid(&ctx->vbus_gpio))
dm_gpio_set_value(&ctx->vbus_gpio, 1);
#endif
setup_usb_phy(ctx->usb);

View File

@@ -72,8 +72,8 @@ struct fdt_usb {
enum usb_init_type init_type;
enum dr_mode dr_mode; /* dual role mode */
enum periph_id periph_id;/* peripheral id */
struct fdt_gpio_state vbus_gpio; /* GPIO for vbus enable */
struct fdt_gpio_state phy_reset_gpio; /* GPIO to reset ULPI phy */
struct gpio_desc vbus_gpio; /* GPIO for vbus enable */
struct gpio_desc phy_reset_gpio; /* GPIO to reset ULPI phy */
};
static struct fdt_usb port[USB_PORTS_MAX]; /* List of valid USB ports */
@@ -252,17 +252,14 @@ static void set_up_vbus(struct fdt_usb *config, enum usb_init_type init)
return;
}
if (fdt_gpio_isvalid(&config->vbus_gpio)) {
if (dm_gpio_is_valid(&config->vbus_gpio)) {
int vbus_value;
fdtdec_setup_gpio(&config->vbus_gpio);
vbus_value = (init == USB_INIT_HOST);
dm_gpio_set_value(&config->vbus_gpio, vbus_value);
vbus_value = (init == USB_INIT_HOST) ^
!!(config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW);
gpio_direction_output(config->vbus_gpio.gpio, vbus_value);
debug("set_up_vbus: GPIO %d %d\n", config->vbus_gpio.gpio,
vbus_value);
debug("set_up_vbus: GPIO %d %d\n",
gpio_get_number(&config->vbus_gpio), vbus_value);
}
}
@@ -360,7 +357,7 @@ static int init_utmi_usb_controller(struct fdt_usb *config,
* mux must be switched to actually use a_sess_vld threshold.
*/
if (config->dr_mode == DR_MODE_OTG &&
fdt_gpio_isvalid(&config->vbus_gpio))
dm_gpio_is_valid(&config->vbus_gpio))
clrsetbits_le32(&usbctlr->usb1_legacy_ctrl,
VBUS_SENSE_CTL_MASK,
VBUS_SENSE_CTL_A_SESS_VLD << VBUS_SENSE_CTL_SHIFT);
@@ -569,11 +566,10 @@ static int init_ulpi_usb_controller(struct fdt_usb *config,
clock_set_pllout(CLOCK_ID_PERIPH, PLL_OUT4, CONFIG_ULPI_REF_CLK);
/* reset ULPI phy */
if (fdt_gpio_isvalid(&config->phy_reset_gpio)) {
fdtdec_setup_gpio(&config->phy_reset_gpio);
gpio_direction_output(config->phy_reset_gpio.gpio, 0);
if (dm_gpio_is_valid(&config->phy_reset_gpio)) {
dm_gpio_set_value(&config->phy_reset_gpio, 0);
mdelay(5);
gpio_set_value(config->phy_reset_gpio.gpio, 1);
dm_gpio_set_value(&config->phy_reset_gpio, 1);
}
/* Reset the usb controller */
@@ -685,14 +681,16 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
debug("%s: Missing/invalid peripheral ID\n", __func__);
return -FDT_ERR_NOTFOUND;
}
fdtdec_decode_gpio(blob, node, "nvidia,vbus-gpio", &config->vbus_gpio);
fdtdec_decode_gpio(blob, node, "nvidia,phy-reset-gpio",
&config->phy_reset_gpio);
gpio_request_by_name_nodev(blob, node, "nvidia,vbus-gpio", 0,
&config->vbus_gpio, GPIOD_IS_OUT);
gpio_request_by_name_nodev(blob, node, "nvidia,phy-reset-gpio", 0,
&config->phy_reset_gpio, GPIOD_IS_OUT);
debug("enabled=%d, legacy_mode=%d, utmi=%d, ulpi=%d, periph_id=%d, "
"vbus=%d, phy_reset=%d, dr_mode=%d\n",
config->enabled, config->has_legacy_mode, config->utmi,
config->ulpi, config->periph_id, config->vbus_gpio.gpio,
config->phy_reset_gpio.gpio, config->dr_mode);
config->ulpi, config->periph_id,
gpio_get_number(&config->vbus_gpio),
gpio_get_number(&config->phy_reset_gpio), config->dr_mode);
return 0;
}

View File

@@ -40,7 +40,7 @@ struct exynos_xhci {
struct exynos_usb3_phy *usb3_phy;
struct xhci_hccr *hcd;
struct dwc3 *dwc3_reg;
struct fdt_gpio_state vbus_gpio;
struct gpio_desc vbus_gpio;
};
static struct exynos_xhci exynos;
@@ -69,7 +69,8 @@ static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos)
exynos->hcd = (struct xhci_hccr *)addr;
/* Vbus gpio */
fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
&exynos->vbus_gpio, GPIOD_IS_OUT);
depth = 0;
node = fdtdec_next_compatible_subnode(blob, node,
@@ -298,9 +299,8 @@ int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor)
#ifdef CONFIG_OF_CONTROL
/* setup the Vbus gpio here */
if (fdt_gpio_isvalid(&ctx->vbus_gpio) &&
!fdtdec_setup_gpio(&ctx->vbus_gpio))
gpio_direction_output(ctx->vbus_gpio.gpio, 1);
if (dm_gpio_is_valid(&ctx->vbus_gpio))
dm_gpio_set_value(&ctx->vbus_gpio, 1);
#endif
ret = exynos_xhci_core_init(ctx);

View File

@@ -149,14 +149,18 @@ static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config)
FDT_LCD_CACHE_WRITE_BACK_FLUSH);
/* These GPIOs are all optional */
fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-enable-gpios",
&config->backlight_en);
fdtdec_decode_gpio(blob, display_node, "nvidia,lvds-shutdown-gpios",
&config->lvds_shutdown);
fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-vdd-gpios",
&config->backlight_vdd);
fdtdec_decode_gpio(blob, display_node, "nvidia,panel-vdd-gpios",
&config->panel_vdd);
gpio_request_by_name_nodev(blob, display_node,
"nvidia,backlight-enable-gpios", 0,
&config->backlight_en, GPIOD_IS_OUT);
gpio_request_by_name_nodev(blob, display_node,
"nvidia,lvds-shutdown-gpios", 0,
&config->lvds_shutdown, GPIOD_IS_OUT);
gpio_request_by_name_nodev(blob, display_node,
"nvidia,backlight-vdd-gpios", 0,
&config->backlight_vdd, GPIOD_IS_OUT);
gpio_request_by_name_nodev(blob, display_node,
"nvidia,panel-vdd-gpios", 0,
&config->panel_vdd, GPIOD_IS_OUT);
return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings",
config->panel_timings, FDT_LCD_TIMINGS);
@@ -196,36 +200,18 @@ static int handle_stage(const void *blob)
*/
funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
fdtdec_setup_gpio(&config.panel_vdd);
fdtdec_setup_gpio(&config.lvds_shutdown);
fdtdec_setup_gpio(&config.backlight_vdd);
fdtdec_setup_gpio(&config.backlight_en);
/*
* TODO: If fdt includes output flag we can omit this code
* since fdtdec_setup_gpio will do it for us.
*/
if (fdt_gpio_isvalid(&config.panel_vdd))
gpio_direction_output(config.panel_vdd.gpio, 0);
if (fdt_gpio_isvalid(&config.lvds_shutdown))
gpio_direction_output(config.lvds_shutdown.gpio, 0);
if (fdt_gpio_isvalid(&config.backlight_vdd))
gpio_direction_output(config.backlight_vdd.gpio, 0);
if (fdt_gpio_isvalid(&config.backlight_en))
gpio_direction_output(config.backlight_en.gpio, 0);
break;
case STAGE_PANEL_VDD:
if (fdt_gpio_isvalid(&config.panel_vdd))
gpio_direction_output(config.panel_vdd.gpio, 1);
if (dm_gpio_is_valid(&config.panel_vdd))
dm_gpio_set_value(&config.panel_vdd, 1);
break;
case STAGE_LVDS:
if (fdt_gpio_isvalid(&config.lvds_shutdown))
gpio_set_value(config.lvds_shutdown.gpio, 1);
if (dm_gpio_is_valid(&config.lvds_shutdown))
dm_gpio_set_value(&config.lvds_shutdown, 1);
break;
case STAGE_BACKLIGHT_VDD:
if (fdt_gpio_isvalid(&config.backlight_vdd))
gpio_set_value(config.backlight_vdd.gpio, 1);
if (dm_gpio_is_valid(&config.backlight_vdd))
dm_gpio_set_value(&config.backlight_vdd, 1);
break;
case STAGE_PWM:
/* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
@@ -235,8 +221,8 @@ static int handle_stage(const void *blob)
pwm_enable(config.pwm_channel, 32768, 0xdf, 1);
break;
case STAGE_BACKLIGHT_EN:
if (fdt_gpio_isvalid(&config.backlight_en))
gpio_set_value(config.backlight_en.gpio, 1);
if (dm_gpio_is_valid(&config.backlight_en))
dm_gpio_set_value(&config.backlight_en, 1);
break;
case STAGE_DONE:
break;