Merge branch 'master' of git://git.denx.de/u-boot-dm
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
source drivers/crypto/fsl/Kconfig
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_EXYNOS_ACE_SHA) += ace_sha.o
|
||||
obj-y += rsa_mod_exp/
|
||||
obj-y += fsl/
|
||||
|
||||
6
drivers/crypto/fsl/Kconfig
Normal file
6
drivers/crypto/fsl/Kconfig
Normal 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.
|
||||
@@ -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
|
||||
|
||||
60
drivers/crypto/fsl/fsl_rsa.c
Normal file
60
drivers/crypto/fsl/fsl_rsa.c
Normal 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",
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
28
drivers/crypto/fsl/rsa_caam.h
Normal file
28
drivers/crypto/fsl/rsa_caam.h
Normal 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
|
||||
5
drivers/crypto/rsa_mod_exp/Kconfig
Normal file
5
drivers/crypto/rsa_mod_exp/Kconfig
Normal 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.
|
||||
7
drivers/crypto/rsa_mod_exp/Makefile
Normal file
7
drivers/crypto/rsa_mod_exp/Makefile
Normal 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
|
||||
39
drivers/crypto/rsa_mod_exp/mod_exp_sw.c
Normal file
39
drivers/crypto/rsa_mod_exp/mod_exp_sw.c
Normal 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",
|
||||
};
|
||||
31
drivers/crypto/rsa_mod_exp/mod_exp_uclass.c
Normal file
31
drivers/crypto/rsa_mod_exp/mod_exp_uclass.c
Normal 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",
|
||||
};
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
108
drivers/i2c/i2c-uclass-compat.c
Normal file
108
drivers/i2c/i2c-uclass-compat.c
Normal 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 */
|
||||
}
|
||||
@@ -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) = {
|
||||
|
||||
367
drivers/i2c/i2c-uniphier-f.c
Normal file
367
drivers/i2c/i2c-uniphier-f.c
Normal 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, ®s->rst);
|
||||
ret = poll_status(®s->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(®s->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, ®s->dttx);
|
||||
|
||||
writel(irq_flags, ®s->ie);
|
||||
writel(irq_flags, ®s->ic);
|
||||
|
||||
debug("start condition\n");
|
||||
writel(I2C_CR_MST | I2C_CR_STA, ®s->cr);
|
||||
|
||||
ret = wait_for_irq(dev, irq_flags, stop);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
while (len--) {
|
||||
debug("sending %x\n", *buf);
|
||||
writel(*buf++, ®s->dttx);
|
||||
|
||||
writel(irq_flags, ®s->ic);
|
||||
|
||||
ret = wait_for_irq(dev, irq_flags, stop);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
writel(irq_flags, ®s->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, ®s->dttx);
|
||||
|
||||
writel(0, ®s->rbc);
|
||||
writel(irq_flags, ®s->ie);
|
||||
writel(irq_flags, ®s->ic);
|
||||
|
||||
debug("start condition\n");
|
||||
writel(I2C_CR_MST | I2C_CR_STA | (len == 1 ? I2C_CR_NACK : 0),
|
||||
®s->cr);
|
||||
|
||||
while (len--) {
|
||||
ret = wait_for_irq(dev, irq_flags, stop);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
*buf++ = readl(®s->dtrx);
|
||||
debug("received %x\n", *(buf - 1));
|
||||
|
||||
if (len == 1)
|
||||
writel(I2C_CR_MST | I2C_CR_NACK, ®s->cr);
|
||||
|
||||
writel(irq_flags, ®s->ic);
|
||||
}
|
||||
|
||||
error:
|
||||
writel(irq_flags, ®s->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, ®s->brst);
|
||||
|
||||
clk_count = dev->fioclk / speed;
|
||||
|
||||
writel(clk_count, ®s->cyc);
|
||||
writel(clk_count / 2, ®s->lctl);
|
||||
writel(clk_count / 2, ®s->ssut);
|
||||
writel(clk_count / 16, ®s->dsut);
|
||||
|
||||
writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, ®s->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
227
drivers/i2c/i2c-uniphier.c
Normal 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,
|
||||
};
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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) = {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user