RFC: dm: Add I2C support
Subsystems (4)
cover RFC: dm: Add I2C support
(Note this is RFC since the uclass interface needs discussion and also because only sandbox is implemented so far. But I thought it best to get this out there as soon as I wrote it as it may influence the PMIC library, etc.)
This series is an initial attempt to add I2C support to driver model. It has become apparent that this is a high priority as it is widely used. It follows along to some extent from the SPI conversion.
Several changes are made from the original I2C implementations.
Firstly It is not necessary to specify the chip address with every call, since each chip knows its own address - it is stored in struct dm_i2c_chip which is attached to each chip on the I2C bus. However, this information *is* passed to the driver since I presume most drivers need it and it would be cumbersome to look up in every call.
Secondly there is no concept of a 'current' I2C bus so all associated logic is removed. With driver model i2c_set_bus_num() and i2c_get_bus_num() are not available. Since the chip device specifies both the bus and the chip address, there is no need for this concept. It also causes problems when one driver changes the current bus and forgets to change it back.
Thirdly initialisation is handled by driver model's normal probe() method on each device so there should be no need for i2c_init_all(), i2c_init(), i2c_init_board(), i2c_board_late_init() and board_i2c_init().
I2C muxes are not yet supported. To support these we will need to maintain state of the current mux settings to avoid resetting every mux every time. Probably we need to add a sandbox I2C mux driver to permit testing of this. This can probably be done later.
Platform data is not yet supported either, only device tree. The U_BOOT_I2C_MKENT_COMPLETE() and U_BOOT_I2C_ADAP_COMPLETE() macros are not used. Also struct i2c_adapter is not defined anymore. This will need to be addressed, perhaps as part of converting over a board that does not use device tree.
This series is available at u-boot-dm/i2c-working.
Simon Glass (12):
dm: core: Allow access to the device's driver_id data
dm: core: Add functions to find parent and OF data
dm: i2c: Add a uclass for I2C
dm: i2c: Implement driver model support in the i2c command
dm: i2c: Add I2C emulation driver for sandbox
dm: i2c: Add a sandbox I2C driver
dm: i2c: Add an I2C EEPROM simulator
dm: i2c: config: Enable I2C for sandbox using driver model
dm: i2c: dts: Add an I2C bus for sandbox
dm: WIP: EEPROM driver
dm: i2c: Add tests for I2C
dm: i2c: tegra: Convert to driver model for I2C for seaboard
arch/arm/cpu/tegra20-common/pmu.c | 21 +- arch/arm/include/asm/arch-tegra/tegra_i2c.h | 2 +- arch/sandbox/dts/sandbox.dts | 17 ++ board/nvidia/common/board.c | 4 - common/cmd_i2c.c | 312 +++++++++++++++++++++++---- drivers/core/device.c | 10 + drivers/core/lists.c | 17 +- drivers/i2c/Makefile | 2 + drivers/i2c/i2c-emul-uclass.c | 14 ++ drivers/i2c/i2c-uclass.c | 177 ++++++++++++++++ drivers/i2c/sandbox_i2c.c | 148 +++++++++++++ drivers/i2c/tegra_i2c.c | 313 ++++++++++------------------ drivers/misc/Makefile | 4 + drivers/misc/i2c_eeprom.c | 51 +++++ drivers/misc/i2c_eeprom_emul.c | 108 ++++++++++ drivers/power/tps6586x.c | 27 +-- include/config_fallbacks.h | 6 + include/configs/cardhu.h | 2 - include/configs/colibri_t30.h | 2 - include/configs/sandbox.h | 6 + include/configs/seaboard.h | 3 - include/configs/tegra-common.h | 1 + include/configs/tegra20-common.h | 3 - include/dm/device.h | 19 ++ include/dm/uclass-id.h | 3 + include/i2c.h | 252 ++++++++++++++++++++++ include/i2c_eeprom.h | 19 ++ include/tps6586x.h | 2 +- test/dm/Makefile | 1 + test/dm/i2c.c | 100 +++++++++ test/dm/test.dts | 17 ++ 31 files changed, 1373 insertions(+), 290 deletions(-) create mode 100644 drivers/i2c/i2c-emul-uclass.c create mode 100644 drivers/i2c/i2c-uclass.c create mode 100644 drivers/i2c/sandbox_i2c.c create mode 100644 drivers/misc/i2c_eeprom.c create mode 100644 drivers/misc/i2c_eeprom_emul.c create mode 100644 include/i2c_eeprom.h create mode 100644 test/dm/i2c.c
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 1/12 dm: core: Allow access to the device's driver_id data
When the device is created from a device tree node, it matches a compatible string. Allow access to that string and the associated data.
---
drivers/core/device.c | 5 +++++ drivers/core/lists.c | 17 ++++++++++++----- include/dm/device.h | 11 +++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-)
drivers/core/device.c +5 -0
@@ -548,3 +548,8 @@ int device_find_next_child(struct udevice **devp)return 0 ; } + +ulong dev_get_of_data (struct udevice *dev) +{ +return dev->of_id->data; +}
drivers/core/lists.c +12 -5
@@ -96,22 +96,26 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only)* tree error */ static int driver_check_compatible (const void *blob,int offset, -const struct udevice_id *of_match) +const struct udevice_id *of_match, +const struct udevice_id **of_idp) {int ret; + *of_idp =NULL ;if (!of_match)return -ENOENT ;while (of_match->compatible) { ret =fdt_node_check_compatible (blob, offset, of_match->compatible); -if (!ret) +if (!ret) { + *of_idp = of_match;return 0 ; -else if (ret == -FDT_ERR_NOTFOUND ) + }else if (ret == -FDT_ERR_NOTFOUND ) {return -ENODEV ; -else if (ret <0 ) + }else if (ret <0 ) {return -EINVAL ; + } of_match++; }
@@ -123,6 +127,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, { struct driver *driver = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver); +const struct udevice_id *id;struct driver *entry;struct udevice *dev;bool found = false;
@@ -134,7 +139,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,if (devp) *devp =NULL ;for (entry = driver; entry != driver + n_ents; entry++) { - ret =driver_check_compatible (blob, offset, entry->of_match); + ret =driver_check_compatible (blob, offset, entry->of_match, + &id); name =fdt_get_name (blob, offset,NULL );if (ret == -ENOENT ) {continue ;
@@ -154,6 +160,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,dm_warn ("Error binding driver '%s'\n" , entry->name);return ret; }else { + dev->of_id = id; found = true;if (devp) *devp = dev;
include/dm/device.h +11 -0
@@ -47,6 +47,7 @@ struct driver_info;* @name: Name of device, typically the FDT node name * @platdata: Configuration data for this device * @of_offset: Device tree node offset for this device (- for none) +* @of_id: Pointer to the udevice_id structure which created the device * @parent: Parent of this device, or NULL for the top level device * @priv: Private data for this device * @uclass: Pointer to uclass for this device
@@ -65,6 +66,7 @@ struct udevice {const char *name;void *platdata;int of_offset; +const struct udevice_id *of_id;struct udevice *parent;void *priv;struct uclass *uclass;
@@ -200,6 +202,15 @@ void *dev_get_parentdata(struct udevice *dev);void *dev_get_priv (struct udevice *dev);/** +* dev_get_of_data() - get the device tree data used to bind a device +* +* When a device is bound using a device tree node, it matches a +* particular compatible string as in struct udevice_id. This function +* returns the associated data value for that compatible string +*/ +ulong dev_get_of_data (struct udevice *dev); + +/** * device_get_child() - Get the child of a device by index * * Returns the numbered child, 0 being the first. This does not use
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 2/12 dm: core: Add functions to find parent and OF data
In reply to Simon GlassAdd dev_get_parent() as a convenience to obtain the parent of a device.
---
drivers/core/device.c | 5 +++++ include/dm/device.h | 8 ++++++++ 2 files changed, 13 insertions(+)
drivers/core/device.c +5 -0
@@ -549,6 +549,11 @@ int device_find_next_child(struct udevice **devp)return 0 ; } +struct udevice *dev_get_parent (struct udevice *child) +{ +return child->parent; +} +ulong dev_get_of_data (struct udevice *dev) {return dev->of_id->data;
include/dm/device.h +8 -0
@@ -202,6 +202,14 @@ void *dev_get_parentdata(struct udevice *dev);void *dev_get_priv (struct udevice *dev);/** +* struct dev_get_parent() - Get the parent of a device +* +* @child: Child to check +* @return parent of child, or NULL if this is the root device +*/ +struct udevice *dev_get_parent (struct udevice *child); + +/** * dev_get_of_data() - get the device tree data used to bind a device * * When a device is bound using a device tree node, it matches a
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 3/12 dm: i2c: Add a uclass for I2C
In reply to Simon GlassThe uclass implements the same operations as the current I2C framework but makes some changes to make it fit driver model better:
- Remove the chip address from API calls
- Remove the address length from API calls
- Remove concept of 'current' I2C bus
- Drop all existing init functions
---
drivers/i2c/Makefile | 1 + drivers/i2c/i2c-uclass.c | 177 +++++++++++++++++++++++++++++++ include/config_fallbacks.h | 6 ++ include/dm/uclass-id.h | 1 + include/i2c.h | 252 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 437 insertions(+) create mode 100644 drivers/i2c/i2c-uclass.c
drivers/i2c/Makefile +1 -0
@@ -4,6 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_DM_I2C) += i2c-uclass.o obj-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o obj-$(CONFIG_DW_I2C) += designware_i2c.o
drivers/i2c/i2c-uclass.c new file +177 -0
177 lines not on this page · raw message
include/config_fallbacks.h +6 -0
@@ -91,4 +91,10 @@#undef CONFIG_IMAGE_FORMAT_LEGACY#endif +#ifdef CONFIG_DM_I2C +# ifdef CONFIG_SYS_I2C +# error "Cannot define CONFIG_SYS_I2C when CONFIG_DM_I2C is used" +# endif +#endif +#endif /* __CONFIG_FALLBACKS_H */
include/dm/uclass-id.h +1 -0
@@ -28,6 +28,7 @@ enum uclass_id {UCLASS_SPI_GENERIC ,/* Generic SPI flash target */ UCLASS_SPI_FLASH ,/* SPI flash */ UCLASS_CROS_EC ,/* Chrome OS EC */ +UCLASS_I2C ,/* I2C bus */ UCLASS_COUNT , UCLASS_INVALID = -1,
include/i2c.h +252 -0
262 lines not on this page · raw message
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 3/12 dm: i2c: Add a uclass for I2C
Hello Simon,
Am 13.10.2014 07:39, schrieb Simon Glass:
Quoted 11 lines
The uclass implements the same operations as the current I2C framework but makes some changes to make it fit driver model better:
- Remove the chip address from API calls
- Remove the address length from API calls
- Remove concept of 'current' I2C bus
- Drop all existing init functionsSigned-off-by Simon Glass <[email protected]>---
Quoted 7 lines
drivers/i2c/Makefile | 1 + drivers/i2c/i2c-uclass.c | 177 +++++++++++++++++++++++++++++++ include/config_fallbacks.h | 6 ++ include/dm/uclass-id.h | 1 + include/i2c.h | 252 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 437 insertions(+)create mode 100644
drivers/i2c/i2c-uclass.c
only nitpick ...
[...]
Quoted 80 lines
drivers/i2c/i2c-uclass.c new file +74
-0@@ -0,0 +1,177 @@ +/* +* Copyright (c) 2014 Google, Inc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <dm/device-internal.h> +#include <dm/root.h> + +DECLARE_GLOBAL_DATA_PTR ; + +int i2c_read (struct udevice *dev,uint addr,uint8_t *buffer,int len) +{ +struct dm_i2c_chip *chip =dev_get_parentdata (dev); +struct udevice *bus =dev_get_parent (dev); +struct dm_i2c_ops *ops =i2c_get_ops (bus); + +if (!ops->read) +return -ENOSYS ; + +return ops->read (bus, chip->chip_addr, addr, chip->addr_len, buffer, + len); +} + +int i2c_write (struct udevice *dev,uint addr,const uint8_t *buffer,int len) +{ +struct dm_i2c_chip *chip =dev_get_parentdata (dev); +struct udevice *bus =dev_get_parent (dev); +struct dm_i2c_ops *ops =i2c_get_ops (bus); + +if (!ops->write) +return -ENOSYS ; + +return ops->write (bus, chip->chip_addr, addr, chip->addr_len, buffer, + len); +} + +int i2c_get_chip (struct udevice *bus,uint chip_addr,struct udevice **devp) +{ +struct udevice *dev; + +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); +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); +if (ret) +return ret; + *devp = dev; +return 0 ; + } + } + +return -ENODEV ; +} + +int i2c_probe (struct udevice *bus,uint chip) +{ +struct dm_i2c_ops *ops =i2c_get_ops (bus); +struct udevice *dev; +int ret;
drivers/i2c/i2c-uclass.c line 84
Quoted 10 lines
drivers/i2c/i2c-uclass.c new file +10
-0+ +if (!ops->probe) +return -ENODEV ; + +/* First probe that chip */ + ret = ops->probe (bus, chip); +if (ret) +return ret; + +/* The cihp was found, see if we have a driver, and probe it */
s/cihp/chip
[...]
bye,
Heiko
Signature · 2 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
RFC PATCH 4/12 dm: i2c: Implement driver model support in the i2c command
In reply to Simon GlassThe concept of a 'current bus' is now implemented in the command line rather than in the uclass. Also the address length does not need to be specified with each command - really we should consider dropping this from most commands but it works OK for now.
---
common/cmd_i2c.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 267 insertions(+), 45 deletions(-)
common/cmd_i2c.c +267 -45
@@ -69,8 +69,10 @@#include <bootretry.h> #include <cli.h> #include <command.h> +#include <dm.h> #include <edid.h> #include <environment.h> +#include <errno.h> #include <i2c.h> #include <malloc.h> #include <asm/byteorder.h>
@@ -117,6 +119,60 @@ static uchar i2c_no_probes[] = CONFIG_SYS_I2C_NOPROBES;#define DISP_LINE_LEN 16 +/* +* Default for driver model is to use the chip's existing address length. +* For legacy code, this is not stored, so we need to use a suitable +* default. +*/ +#ifdef CONFIG_DM_I2C +#define DEFAULT_ADDR_LEN (-1) +#else +#define DEFAULT_ADDR_LEN 1 +#endif + +#ifdef CONFIG_DM_I2C +static struct udevice *i2c_cur_bus; + +static int i2c_set_bus_num (unsigned int busnum) +{ +struct udevice *bus; +int ret; + + ret =uclass_get_device_by_seq (UCLASS_I2C , busnum, &bus); +if (ret) { +debug ("%s: No bus %d\n" , __func__, busnum); +return ret; + } + i2c_cur_bus = bus; + +return 0 ; +} + +static int i2c_get_cur_bus (struct udevice **busp) +{ +if (!i2c_cur_bus) { +puts ("No I2C bus selected\n" ); +return -ENODEV ; + } + *busp = i2c_cur_bus; + +return 0 ; +} + +static int i2c_get_cur_bus_chip (uint chip_addr,struct udevice **devp) +{ +struct udevice *bus; +int ret; + + ret =i2c_get_cur_bus (&bus); +if (ret) +return ret; + +return i2c_get_chip (bus, chip_addr, devp); +} + +#endif +/** * i2c_init_board() - Board-specific I2C bus init *
@@ -143,7 +199,7 @@ void i2c_init_board(void)* * Returns I2C bus speed in Hz. */ -#if !defined(CONFIG_SYS_I2C ) +#if !defined(CONFIG_SYS_I2C ) && !defined(CONFIG_DM_I2C )/* * TODO: Implement architecture-specific get/set functions * Should go away, if we switched completely to new multibus support
@@ -182,12 +238,12 @@ int i2c_set_bus_speed(unsigned int speed)* * Returns the address length. */ -static uint get_alen (char *arg) +static uint get_alen (char *arg,int default_len) {int j;int alen; - alen =1 ; + alen = default_len;for (j =0 ; j <8 ; j++) {if (arg[j] =='.' ) { alen = arg[j+1 ] -'0' ;
@@ -229,6 +285,10 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argvu_char chip;uint devaddr, alen, length;u_char *memaddr; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc !=5 )return CMD_RET_USAGE ;
@@ -243,7 +303,7 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv* 2 bytes long. Some day it might be 3 bytes long :-). */ devaddr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ;
@@ -257,10 +317,18 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv*/ memaddr = (u_char *)simple_strtoul (argv[4 ],NULL ,16 ); -if (i2c_read (chip, devaddr, alen, memaddr, length) !=0 ) { -i2c_report_err (-1 ,I2C_ERR_READ ); -return 1 ; - } +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (!ret) + ret =i2c_read (dev, devaddr, memaddr, length); +#else + ret =i2c_read (chip, devaddr, alen, memaddr, length); +#endif +if (ret) +return i2c_report_err (ret,I2C_ERR_READ ); +return 0 ; }
@@ -269,6 +337,10 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[u_char chip;uint devaddr, alen, length;u_char *memaddr; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc !=5 )return cmd_usage (cmdtp);
@@ -288,7 +360,7 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[* 2 bytes long. Some day it might be 3 bytes long :-). */ devaddr =simple_strtoul (argv[3 ],NULL ,16 ); - alen =get_alen (argv[3 ]); + alen =get_alen (argv[3 ],DEFAULT_ADDR_LEN );if (alen >3 )return cmd_usage (cmdtp);
@@ -297,10 +369,22 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[*/ length =simple_strtoul (argv[4 ],NULL ,16 ); +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE ); +#endif +while (length-- >0 ) { -if (i2c_write (chip, devaddr++, alen, memaddr++,1 ) !=0 ) { -return i2c_report_err (-1 ,I2C_ERR_WRITE ); - } +#ifdef CONFIG_DM_I2C + ret =i2c_write (dev, devaddr++, memaddr++,1 ); +#else + ret =i2c_write (chip, devaddr++, alen, memaddr++,1 ); +#endif +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE );/* * No write delay with FRAM devices. */
@@ -329,6 +413,10 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]u_char chip;uint addr, alen, length;int j, nbytes, linebytes; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif /* We use the last specified parameters, unless new ones are * entered.
@@ -356,7 +444,7 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* 2 bytes long. Some day it might be 3 bytes long :-). */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ;
@@ -368,6 +456,14 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] length =simple_strtoul (argv[3 ],NULL ,16 ); } +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_READ ); +#endif +/* * Print the lines. *
@@ -381,8 +477,13 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] linebytes = (nbytes >DISP_LINE_LEN ) ?DISP_LINE_LEN : nbytes; -if (i2c_read (chip, addr, alen, linebuf, linebytes) !=0 ) -i2c_report_err (-1 ,I2C_ERR_READ ); +#ifdef CONFIG_DM_I2C + ret =i2c_read (dev, addr, linebuf, linebytes); +#else + ret =i2c_read (chip, addr, alen, linebuf, linebytes); +#endif +if (ret) +i2c_report_err (ret,I2C_ERR_READ );else {printf ("%04x:" , addr); cp = linebuf;
@@ -432,6 +533,10 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]uint alen;uchar byte;int count; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if ((argc <4 ) || (argc >5 ))return CMD_RET_USAGE ;
@@ -445,10 +550,17 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* Address is always specified. */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ; +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE ); +#endif /* * Value to write is always specified. */
@@ -463,8 +575,13 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] count =1 ;while (count-- >0 ) { -if (i2c_write (chip, addr++, alen, &byte,1 ) !=0 ) -i2c_report_err (-1 ,I2C_ERR_WRITE ); +#ifdef CONFIG_DM_I2C + ret =i2c_write (dev, addr++, &byte,1 ); +#else + ret =i2c_write (chip, addr++, alen, &byte,1 ); +#endif +if (ret) +i2c_report_err (ret,I2C_ERR_WRITE );/* * Wait for the write to complete. The write can take * up to 10mSec (we allow a little more time).
@@ -504,6 +621,10 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]uchar byte;ulong crc;ulong err; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc <4 )return CMD_RET_USAGE ;
@@ -517,10 +638,17 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* Address is always specified. */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ; +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_READ ); +#endif /* * Count is always specified */
@@ -534,13 +662,18 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] crc =0 ; err =0 ;while (count-- >0 ) { -if (i2c_read (chip, addr, alen, &byte,1 ) !=0 ) +#ifdef CONFIG_DM_I2C + ret =i2c_read (dev, addr, &byte,1 ); +#else + ret =i2c_read (chip, addr, alen, &byte,1 ); +#endif +if (ret) err++; crc =crc32 (crc, &byte,1 ); addr++; }if (err >0 ) -i2c_report_err (-1 ,I2C_ERR_READ ); +i2c_report_err (ret,I2C_ERR_READ );else printf ("%08lx\n" , crc);
@@ -572,6 +705,10 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argulong data;int size =1 ;int nbytes; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc !=3 )return CMD_RET_USAGE ;
@@ -601,19 +738,32 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg* Address is always specified. */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ; } +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE ); +#endif +/* * Print the address, followed by value. Then accept input for * the next value. A non-converted value exits. */ do { printf("%08lx:", addr); - if (i2c_read(chip, addr, alen, (uchar *)&data, size) != 0) - i2c_report_err(-1, I2C_ERR_READ); +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, (uchar *)&data, size); +#else + ret = i2c_read(chip, addr, alen, (uchar *)&data, size); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_READ); else { data = cpu_to_be32(data); if (size == 1)
@@ -655,8 +805,15 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg* good enough to not time out */ bootretry_reset_cmd_timeout (); -if (i2c_write (chip, addr, alen, (uchar *)&data, size) !=0 ) -i2c_report_err (-1 ,I2C_ERR_WRITE ); +#ifdef CONFIG_DM_I2C + ret =i2c_write (dev, addr, (uchar *)&data, + size); +#else + ret =i2c_write (chip, addr, alen, + (uchar *)&data, size); +#endif +if (ret) +i2c_report_err (ret,I2C_ERR_WRITE );#ifdef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS udelay (CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS *1000 );#endif
@@ -697,6 +854,13 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argvint k, skip;unsigned int bus =GET_BUS_NUM ;#endif /* NOPROBES */ +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *bus; + +if (i2c_get_cur_bus (&bus)) +return CMD_RET_FAILURE ; +#endif if (argc ==2 ) addr =simple_strtol (argv[1 ],0 ,16 );
@@ -717,7 +881,12 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argvif (skip)continue ;#endif -if (i2c_probe (j) ==0 ) { +#ifdef CONFIG_DM_I2C + ret =i2c_probe (bus, j); +#else + ret =i2c_probe (j); +#endif +if (ret ==0 ) {printf (" %02X" , j); found++; }
@@ -759,6 +928,10 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]uint length;u_char bytes[16 ];int delay; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc <3 )return CMD_RET_USAGE ;
@@ -772,9 +945,16 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* Address is always specified. */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ; +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE ); +#endif /* * Length is the number of objects, not number of bytes.
@@ -794,8 +974,13 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* Run the loop... */ while (1 ) { -if (i2c_read (chip, addr, alen, bytes, length) !=0 ) -i2c_report_err (-1 ,I2C_ERR_READ ); +#ifdef CONFIG_DM_I2C + ret =i2c_read (dev, addr, bytes, length); +#else + ret =i2c_read (chip, addr, alen, bytes, length); +#endif +if (ret) +i2c_report_err (ret,I2C_ERR_READ );udelay (delay); }
@@ -1345,6 +1530,10 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) {u_char chip;struct edid1_info edid; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc <2 ) {cmd_usage (cmdtp);
@@ -1352,10 +1541,15 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) } chip =simple_strtoul (argv[1 ],NULL ,16 ); -if (i2c_read (chip,0 ,1 , (uchar *)&edid,sizeof (edid)) !=0 ) { -i2c_report_err (-1 ,I2C_ERR_READ ); -return 1 ; - } +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret) + ret =i2c_read (dev,0 , (uchar *)&edid,sizeof (edid)); +#else + ret =i2c_read (chip,0 ,1 , (uchar *)&edid,sizeof (edid)); +#endif +if (ret) +return i2c_report_err (ret,I2C_ERR_READ );if (edid_check_info (&edid)) {puts ("Content isn't valid EDID.\n" );
@@ -1437,17 +1631,28 @@ static int do_i2c_show_bus(cmd_tbl_t *cmdtp, int flag, int argc,* Returns zero on success, CMD_RET_USAGE in case of misuse and negative * on error. */ -#if defined(CONFIG_SYS_I2C ) || defined(CONFIG_I2C_MULTI_BUS ) +#if defined(CONFIG_SYS_I2C ) || defined(CONFIG_I2C_MULTI_BUS ) || \ + defined(CONFIG_DM_I2C )static int do_i2c_bus_num (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) {int ret =0 ; -unsigned int bus_no; +int bus_no; -if (argc ==1 ) +if (argc ==1 ) {/* querying current setting */ -printf ("Current bus is %d\n" ,i2c_get_bus_num ()); -else { +#ifdef CONFIG_DM_I2C +struct udevice *bus; + +if (!i2c_get_cur_bus (&bus)) + bus_no = bus->seq; +else + bus_no =-1 ; +#else + bus_no =i2c_get_bus_num (); +#endif +printf ("Current bus is %d\n" , bus_no); + }else { bus_no =simple_strtoul (argv[1 ],NULL ,10 );#if defined(CONFIG_SYS_I2C )if (bus_no >=CONFIG_SYS_NUM_I2C_BUSES ) {
@@ -1478,13 +1683,28 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const {int speed, ret=0 ; -if (argc ==1 ) +#ifdef CONFIG_DM_I2C +struct udevice *bus; + +if (i2c_get_cur_bus (&bus)) +return 1 ; +#endif +if (argc ==1 ) { +#ifdef CONFIG_DM_I2C + speed =i2c_get_bus_speed (bus); +#else + speed =i2c_get_bus_speed (); +#endif /* querying current speed */ -printf ("Current bus speed=%d\n" ,i2c_get_bus_speed ()); -else { +printf ("Current bus speed=%d\n" , speed); + }else { speed =simple_strtoul (argv[1 ],NULL ,10 );printf ("Setting bus speed to %d Hz\n" , speed); +#ifdef CONFIG_DM_I2C + ret =i2c_set_bus_speed (bus, speed); +#else ret =i2c_set_bus_speed (speed); +#endif if (ret)printf ("Failure changing bus speed (%d)\n" , ret); }
@@ -1532,7 +1752,9 @@ static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])*/ static int do_i2c_reset (cmd_tbl_t * cmdtp,int flag,int argc,char *const argv[]) { -#if defined(CONFIG_SYS_I2C ) +#if defined(CONFIG_DM_I2C ) +/* TODO(sjg at chromium.org): What should we do here? */ +#elif defined(CONFIG_SYS_I2C )i2c_init (I2C_ADAP ->speed,I2C_ADAP ->slaveaddr);#else i2c_init (CONFIG_SYS_I2C_SPEED ,CONFIG_SYS_I2C_SLAVE );
@@ -1546,7 +1768,7 @@ static cmd_tbl_t cmd_i2c_sub[] = {#endif U_BOOT_CMD_MKENT(crc32, 3, 1, do_i2c_crc, "", ""),#if defined(CONFIG_SYS_I2C ) || \ - defined(CONFIG_I2C_MULTI_BUS ) + defined(CONFIG_I2C_MULTI_BUS ) || defined(CONFIG_DM_I2C ) U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""),#endif /* CONFIG_I2C_MULTI_BUS */ #if defined(CONFIG_I2C_EDID )
@@ -1610,7 +1832,7 @@ static char i2c_help_text[] =#endif "crc32 chip address[.0, .1, .2] count - compute CRC32 checksum\n"#if defined(CONFIG_SYS_I2C ) || \ - defined(CONFIG_I2C_MULTI_BUS ) + defined(CONFIG_I2C_MULTI_BUS ) || defined(CONFIG_DM_I2C ) "i2c dev [dev] - show or set current I2C bus\n"#endif /* CONFIG_I2C_MULTI_BUS */ #if defined(CONFIG_I2C_EDID )
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 4/12 dm: i2c: Implement driver model support in the i2c command
Hello Simon,
Am 13.10.2014 07:39, schrieb Simon Glass:
Quoted 584 lines
The concept of a 'current bus' is now implemented in the command line rather than in the uclass. Also the address length does not need to be specified with each command - really we should consider dropping this from most commands but it works OK for now.
Signed-off-by Simon Glass <[email protected]>---
common/cmd_i2c.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 267 insertions(+), 45 deletions(-)common/cmd_i2c.c +262
-42@@ -69,8 +69,10 @@#include <bootretry.h> #include <cli.h> #include <command.h> +#include <dm.h> #include <edid.h> #include <environment.h> +#include <errno.h> #include <i2c.h> #include <malloc.h> #include <asm/byteorder.h> @@ -117,6 +119,60 @@ static uchar i2c_no_probes[] = CONFIG_SYS_I2C_NOPROBES;#define DISP_LINE_LEN 16 +/* +* Default for driver model is to use the chip's existing address length. +* For legacy code, this is not stored, so we need to use a suitable +* default. +*/ +#ifdef CONFIG_DM_I2C +#define DEFAULT_ADDR_LEN (-1) +#else +#define DEFAULT_ADDR_LEN 1 +#endif + +#ifdef CONFIG_DM_I2C +static struct udevice *i2c_cur_bus; + +static int i2c_set_bus_num (unsigned int busnum) +{ +struct udevice *bus; +int ret; + + ret =uclass_get_device_by_seq (UCLASS_I2C , busnum, &bus); +if (ret) { +debug ("%s: No bus %d\n" , __func__, busnum); +return ret; + } + i2c_cur_bus = bus; + +return 0 ; +} + +static int i2c_get_cur_bus (struct udevice **busp) +{ +if (!i2c_cur_bus) { +puts ("No I2C bus selected\n" ); +return -ENODEV ; + } + *busp = i2c_cur_bus; + +return 0 ; +} + +static int i2c_get_cur_bus_chip (uint chip_addr,struct udevice **devp) +{ +struct udevice *bus; +int ret; + + ret =i2c_get_cur_bus (&bus); +if (ret) +return ret; + +return i2c_get_chip (bus, chip_addr, devp); +} + +#endif +/** * i2c_init_board() - Board-specific I2C bus init * @@ -143,7 +199,7 @@ void i2c_init_board(void)* * Returns I2C bus speed in Hz. */ -#if !defined(CONFIG_SYS_I2C ) +#if !defined(CONFIG_SYS_I2C ) && !defined(CONFIG_DM_I2C )/* * TODO: Implement architecture-specific get/set functions * Should go away, if we switched completely to new multibus support @@ -182,12 +238,12 @@ int i2c_set_bus_speed(unsigned int speed)* * Returns the address length. */ -static uint get_alen (char *arg) +static uint get_alen (char *arg,int default_len) {int j;int alen; - alen =1 ; + alen = default_len;for (j =0 ; j <8 ; j++) {if (arg[j] =='.' ) { alen = arg[j+1 ] -'0' ;@@ -229,6 +285,10 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argvu_char chip;uint devaddr, alen, length;u_char *memaddr; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc !=5 )return CMD_RET_USAGE ;@@ -243,7 +303,7 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv* 2 bytes long. Some day it might be 3 bytes long :-). */ devaddr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ;@@ -257,10 +317,18 @@ static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv*/ memaddr = (u_char *)simple_strtoul (argv[4 ],NULL ,16 ); -if (i2c_read (chip, devaddr, alen, memaddr, length) !=0 ) { -i2c_report_err (-1 ,I2C_ERR_READ ); -return 1 ; - } +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (!ret) + ret =i2c_read (dev, devaddr, memaddr, length); +#else + ret =i2c_read (chip, devaddr, alen, memaddr, length); +#endif +if (ret) +return i2c_report_err (ret,I2C_ERR_READ ); +return 0 ; }@@ -269,6 +337,10 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[u_char chip;uint devaddr, alen, length;u_char *memaddr; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc !=5 )return cmd_usage (cmdtp);@@ -288,7 +360,7 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[* 2 bytes long. Some day it might be 3 bytes long :-). */ devaddr =simple_strtoul (argv[3 ],NULL ,16 ); - alen =get_alen (argv[3 ]); + alen =get_alen (argv[3 ],DEFAULT_ADDR_LEN );if (alen >3 )return cmd_usage (cmdtp);@@ -297,10 +369,22 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[*/ length =simple_strtoul (argv[4 ],NULL ,16 ); +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE ); +#endif +while (length-- >0 ) { -if (i2c_write (chip, devaddr++, alen, memaddr++,1 ) !=0 ) { -return i2c_report_err (-1 ,I2C_ERR_WRITE ); - } +#ifdef CONFIG_DM_I2C + ret =i2c_write (dev, devaddr++, memaddr++,1 ); +#else + ret =i2c_write (chip, devaddr++, alen, memaddr++,1 ); +#endif +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE );/* * No write delay with FRAM devices. */ @@ -329,6 +413,10 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]u_char chip;uint addr, alen, length;int j, nbytes, linebytes; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif /* We use the last specified parameters, unless new ones are * entered. @@ -356,7 +444,7 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* 2 bytes long. Some day it might be 3 bytes long :-). */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ;@@ -368,6 +456,14 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] length =simple_strtoul (argv[3 ],NULL ,16 ); } +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_READ ); +#endif +/* * Print the lines. * @@ -381,8 +477,13 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] linebytes = (nbytes >DISP_LINE_LEN ) ?DISP_LINE_LEN : nbytes; -if (i2c_read (chip, addr, alen, linebuf, linebytes) !=0 ) -i2c_report_err (-1 ,I2C_ERR_READ ); +#ifdef CONFIG_DM_I2C + ret =i2c_read (dev, addr, linebuf, linebytes); +#else + ret =i2c_read (chip, addr, alen, linebuf, linebytes); +#endif +if (ret) +i2c_report_err (ret,I2C_ERR_READ );else {printf ("%04x:" , addr); cp = linebuf;@@ -432,6 +533,10 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]uint alen;uchar byte;int count; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if ((argc <4 ) || (argc >5 ))return CMD_RET_USAGE ;@@ -445,10 +550,17 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* Address is always specified. */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ; +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE ); +#endif /* * Value to write is always specified. */ @@ -463,8 +575,13 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] count =1 ;while (count-- >0 ) { -if (i2c_write (chip, addr++, alen, &byte,1 ) !=0 ) -i2c_report_err (-1 ,I2C_ERR_WRITE ); +#ifdef CONFIG_DM_I2C + ret =i2c_write (dev, addr++, &byte,1 ); +#else + ret =i2c_write (chip, addr++, alen, &byte,1 ); +#endif +if (ret) +i2c_report_err (ret,I2C_ERR_WRITE );/* * Wait for the write to complete. The write can take * up to 10mSec (we allow a little more time). @@ -504,6 +621,10 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]uchar byte;ulong crc;ulong err; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc <4 )return CMD_RET_USAGE ;@@ -517,10 +638,17 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* Address is always specified. */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ; +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_READ ); +#endif /* * Count is always specified */ @@ -534,13 +662,18 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] crc =0 ; err =0 ;while (count-- >0 ) { -if (i2c_read (chip, addr, alen, &byte,1 ) !=0 ) +#ifdef CONFIG_DM_I2C + ret =i2c_read (dev, addr, &byte,1 ); +#else + ret =i2c_read (chip, addr, alen, &byte,1 ); +#endif +if (ret) err++; crc =crc32 (crc, &byte,1 ); addr++; }if (err >0 ) -i2c_report_err (-1 ,I2C_ERR_READ ); +i2c_report_err (ret,I2C_ERR_READ );else printf ("%08lx\n" , crc);@@ -572,6 +705,10 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argulong data;int size =1 ;int nbytes; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc !=3 )return CMD_RET_USAGE ;@@ -601,19 +738,32 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg* Address is always specified. */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ; } +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE ); +#endif +/* * Print the address, followed by value. Then accept input for * the next value. A non-converted value exits. */ do { printf("%08lx:", addr); - if (i2c_read(chip, addr, alen, (uchar *)&data, size) != 0) - i2c_report_err(-1, I2C_ERR_READ); +#ifdef CONFIG_DM_I2C + ret = i2c_read(dev, addr, (uchar *)&data, size); +#else + ret = i2c_read(chip, addr, alen, (uchar *)&data, size); +#endif + if (ret) + i2c_report_err(ret, I2C_ERR_READ); else { data = cpu_to_be32(data); if (size == 1)@@ -655,8 +805,15 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg* good enough to not time out */ bootretry_reset_cmd_timeout (); -if (i2c_write (chip, addr, alen, (uchar *)&data, size) !=0 ) -i2c_report_err (-1 ,I2C_ERR_WRITE ); +#ifdef CONFIG_DM_I2C + ret =i2c_write (dev, addr, (uchar *)&data, + size); +#else + ret =i2c_write (chip, addr, alen, + (uchar *)&data, size); +#endif +if (ret) +i2c_report_err (ret,I2C_ERR_WRITE );#ifdef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS udelay (CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS *1000 );#endif @@ -697,6 +854,13 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argvint k, skip;unsigned int bus =GET_BUS_NUM ;#endif /* NOPROBES */ +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *bus; + +if (i2c_get_cur_bus (&bus)) +return CMD_RET_FAILURE ; +#endif if (argc ==2 ) addr =simple_strtol (argv[1 ],0 ,16 );@@ -717,7 +881,12 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argvif (skip)continue ;#endif -if (i2c_probe (j) ==0 ) { +#ifdef CONFIG_DM_I2C + ret =i2c_probe (bus, j); +#else + ret =i2c_probe (j); +#endif +if (ret ==0 ) {printf (" %02X" , j); found++; }@@ -759,6 +928,10 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]uint length;u_char bytes[16 ];int delay; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc <3 )return CMD_RET_USAGE ;@@ -772,9 +945,16 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* Address is always specified. */ addr =simple_strtoul (argv[2 ],NULL ,16 ); - alen =get_alen (argv[2 ]); + alen =get_alen (argv[2 ],DEFAULT_ADDR_LEN );if (alen >3 )return CMD_RET_USAGE ; +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret && alen !=-1 ) + ret =i2c_set_addr_len (dev, alen); +if (ret) +return i2c_report_err (ret,I2C_ERR_WRITE ); +#endif /* * Length is the number of objects, not number of bytes. @@ -794,8 +974,13 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]* Run the loop... */ while (1 ) { -if (i2c_read (chip, addr, alen, bytes, length) !=0 ) -i2c_report_err (-1 ,I2C_ERR_READ ); +#ifdef CONFIG_DM_I2C + ret =i2c_read (dev, addr, bytes, length); +#else + ret =i2c_read (chip, addr, alen, bytes, length); +#endif +if (ret) +i2c_report_err (ret,I2C_ERR_READ );udelay (delay); }@@ -1345,6 +1530,10 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) {u_char chip;struct edid1_info edid; +int ret; +#ifdef CONFIG_DM_I2C +struct udevice *dev; +#endif if (argc <2 ) {cmd_usage (cmdtp);@@ -1352,10 +1541,15 @@ int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) } chip =simple_strtoul (argv[1 ],NULL ,16 ); -if (i2c_read (chip,0 ,1 , (uchar *)&edid,sizeof (edid)) !=0 ) { -i2c_report_err (-1 ,I2C_ERR_READ ); -return 1 ; - } +#ifdef CONFIG_DM_I2C + ret =i2c_get_cur_bus_chip (chip, &dev); +if (!ret) + ret =i2c_read (dev,0 , (uchar *)&edid,sizeof (edid)); +#else + ret =i2c_read (chip,0 ,1 , (uchar *)&edid,sizeof (edid)); +#endif +if (ret) +return i2c_report_err (ret,I2C_ERR_READ );if (edid_check_info (&edid)) {puts ("Content isn't valid EDID.\n" );@@ -1437,17 +1631,28 @@ static int do_i2c_show_bus(cmd_tbl_t *cmdtp, int flag, int argc,* Returns zero on success, CMD_RET_USAGE in case of misuse and negative * on error. */ -#if defined(CONFIG_SYS_I2C ) || defined(CONFIG_I2C_MULTI_BUS ) +#if defined(CONFIG_SYS_I2C ) || defined(CONFIG_I2C_MULTI_BUS ) || \ + defined(CONFIG_DM_I2C )static int do_i2c_bus_num (cmd_tbl_t *cmdtp,int flag,int argc,char *const argv[]) {int ret =0 ; -unsigned int bus_no; +int bus_no; -if (argc ==1 ) +if (argc ==1 ) {/* querying current setting */ -printf ("Current bus is %d\n" ,i2c_get_bus_num ()); -else { +#ifdef CONFIG_DM_I2C +struct udevice *bus; + +if (!i2c_get_cur_bus (&bus)) + bus_no = bus->seq; +else + bus_no =-1 ; +#else + bus_no =i2c_get_bus_num (); +#endif +printf ("Current bus is %d\n" , bus_no); + }else { bus_no =simple_strtoul (argv[1 ],NULL ,10 );#if defined(CONFIG_SYS_I2C )if (bus_no >=CONFIG_SYS_NUM_I2C_BUSES ) {@@ -1478,13 +1683,28 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const {int speed, ret=0 ; -if (argc ==1 ) +#ifdef CONFIG_DM_I2C +struct udevice *bus; + +if (i2c_get_cur_bus (&bus)) +return 1 ; +#endif +if (argc ==1 ) { +#ifdef CONFIG_DM_I2C + speed =i2c_get_bus_speed (bus); +#else + speed =i2c_get_bus_speed (); +#endif /* querying current speed */ -printf ("Current bus speed=%d\n" ,i2c_get_bus_speed ()); -else { +printf ("Current bus speed=%d\n" , speed); + }else { speed =simple_strtoul (argv[1 ],NULL ,10 );printf ("Setting bus speed to %d Hz\n" , speed); +#ifdef CONFIG_DM_I2C + ret =i2c_set_bus_speed (bus, speed); +#else ret =i2c_set_bus_speed (speed); +#endif if (ret)printf ("Failure changing bus speed (%d)\n" , ret); }
common/cmd_i2c.c static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) · line 1756
Quoted 6 lines
common/cmd_i2c.c +2
-1@@ -1532,7 +1752,9 @@ static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])*/ static int do_i2c_reset (cmd_tbl_t * cmdtp,int flag,int argc,char *const argv[]) { -#if defined(CONFIG_SYS_I2C ) +#if defined(CONFIG_DM_I2C ) +/* TODO(sjg at chromium.org): What should we do here? */
This is a good question. I wanted to add in the CONFIG_SYS_I2C case, a possibility to add a i2c deblock function for drivers and call them from here ... Currently the i2c_init_board() is abused (see u-boot:doc/I2C_Edge_Conditions) for this ...
This gets interesting as a lot of SoCs can switch the i2c pins into gpio mode and do then a bitbang deblock of the bus, and if this is finished switch back the pins to i2c mode ...
So maybe we add the following in include/i2c.h for the DM case:
+struct dm_i2c_ops {
+ /**
+ * deblock() - deblock an i2c bus + * + * @bus: Bus to deblock + */
+ int (*deblock)(struct udevice *bus);
and this deblock() gets called here (if defined for an driver).
So we can provide a default soft bitbang deblock function (a good one is in ./board/keymile/common/common.c i2c_make_abort())
which should call a board specific i2c_switch_pin(struct udevice *bus, int mode) with mode = PIN_TO_GPIO_MODE or PIN_TO_I2C_MODE
rough fast proposal:
int i2c_soft_deblock(struct udevice *bus)
{
int ret;
ret = i2c_switch_pin(bus, PIN_TO_GPIO_MODE);
/* boards which could not do softbitbang return here -EPERM */
if (ret)
return ret;
/* call soft bitbang ... */
ret = i2c_soft_deblock()
if (ret)
return ret;
ret = i2c_switch_pin(bus, PIN_TO_GPIO_MODE);
return ret;
}bye,
Heiko
Quoted 23 lines
common/cmd_i2c.c +3
-2+#elif defined(CONFIG_SYS_I2C )i2c_init (I2C_ADAP ->speed,I2C_ADAP ->slaveaddr);#else i2c_init (CONFIG_SYS_I2C_SPEED ,CONFIG_SYS_I2C_SLAVE );@@ -1546,7 +1768,7 @@ static cmd_tbl_t cmd_i2c_sub[] = {#endif U_BOOT_CMD_MKENT(crc32, 3, 1, do_i2c_crc, "", ""),#if defined(CONFIG_SYS_I2C ) || \ - defined(CONFIG_I2C_MULTI_BUS ) + defined(CONFIG_I2C_MULTI_BUS ) || defined(CONFIG_DM_I2C ) U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""),#endif /* CONFIG_I2C_MULTI_BUS */ #if defined(CONFIG_I2C_EDID )@@ -1610,7 +1832,7 @@ static char i2c_help_text[] =#endif "crc32 chip address[.0, .1, .2] count - compute CRC32 checksum\n"#if defined(CONFIG_SYS_I2C ) || \ - defined(CONFIG_I2C_MULTI_BUS ) + defined(CONFIG_I2C_MULTI_BUS ) || defined(CONFIG_DM_I2C ) "i2c dev [dev] - show or set current I2C bus\n"#endif /* CONFIG_I2C_MULTI_BUS */ #if defined(CONFIG_I2C_EDID )
Signature · 2 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
RFC PATCH 5/12 dm: i2c: Add I2C emulation driver for sandbox
In reply to Simon GlassIn order to test I2C we need some sort of emulation interface. Add hooks to allow a driver to emulate an I2C device for sandbox.
---
drivers/i2c/Makefile | 1 + drivers/i2c/i2c-emul-uclass.c | 14 ++++++++++++++ include/dm/uclass-id.h | 1 + 3 files changed, 16 insertions(+) create mode 100644 drivers/i2c/i2c-emul-uclass.c
drivers/i2c/Makefile +1 -0
@@ -27,6 +27,7 @@ obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o +obj-$(CONFIG_SYS_I2C_SANDBOX) += 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
drivers/i2c/i2c-emul-uclass.c new file +14 -0
@@ -0,0 +1,14 @@ +/* +* Copyright (c) 2014 Google, Inc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <dm.h> +#include <i2c.h> + +UCLASS_DRIVER (i2c_emul) = { + .id =UCLASS_I2C_EMUL , + .name ="i2c_emul" , +};
include/dm/uclass-id.h +1 -0
@@ -19,6 +19,7 @@ enum uclass_id {UCLASS_TEST_FDT ,UCLASS_TEST_BUS ,UCLASS_SPI_EMUL ,/* sandbox SPI device emulator */ +UCLASS_I2C_EMUL ,/* sandbox I2C device emulator */ UCLASS_SIMPLE_BUS,/* U-Boot uclasses start here */
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 6/12 dm: i2c: Add a sandbox I2C driver
In reply to Simon GlassThis driver includes some test features such as only supporting certain bus speeds. It passes its I2C traffic through to an emulator.
---
drivers/i2c/Makefile | 2 +- drivers/i2c/sandbox_i2c.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 drivers/i2c/sandbox_i2c.c
drivers/i2c/Makefile +1 -1
@@ -27,7 +27,7 @@ obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o -obj-$(CONFIG_SYS_I2C_SANDBOX) += i2c-emul-uclass.o +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
drivers/i2c/sandbox_i2c.c new file +148 -0
148 lines not on this page · raw message
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 7/12 dm: i2c: Add an I2C EEPROM simulator
In reply to Simon GlassTo enable testing of I2C, add a simple I2C EEPROM simulator for sandbox. It supports reading and writing from a small data store.
---
drivers/misc/Makefile | 3 ++ drivers/misc/i2c_eeprom_emul.c | 108 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 drivers/misc/i2c_eeprom_emul.c
drivers/misc/Makefile +3 -0
@@ -20,6 +20,9 @@ obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NS87308) += ns87308.o obj-$(CONFIG_PDSP188x) += pdsp188x.o +ifdef CONFIG_DM_I2C +obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o +endif obj-$(CONFIG_STATUS_LED) += status_led.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
drivers/misc/i2c_eeprom_emul.c new file +108 -0
108 lines not on this page · raw message
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 8/12 dm: i2c: config: Enable I2C for sandbox using driver model
In reply to Simon GlassEnable the options to bring up I2C on sandbox. Also enable all the available I2C commands for testing purposes.
---
include/configs/sandbox.h | 6 ++++++ 1 file changed, 6 insertions(+)
include/configs/sandbox.h +6 -0
@@ -110,6 +110,12 @@#define CONFIG_SPI_FLASH_STMICRO #define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_DM_I2C +#define CONFIG_CMD_I2C +#define CONFIG_SYS_I2C_SANDBOX +#define CONFIG_I2C_EDID +#define CONFIG_I2C_EEPROM +/* Memory things - we don't really want a memory test */ #define CONFIG_SYS_LOAD_ADDR 0x00000000#define CONFIG_SYS_MEMTEST_START 0x00100000
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 9/12 dm: i2c: dts: Add an I2C bus for sandbox
In reply to Simon GlassAdd an I2C bus to the device tree, with an EEPROM emulator attached to one of the addresses.
---
arch/sandbox/dts/sandbox.dts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
arch/sandbox/dts/sandbox.dts +17 -0
@@ -134,6 +134,23 @@ num-gpios = <20>; }; + i2c at 0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + compatible = "sandbox,i2c"; + clock-frequency = <400000>; + eeprom at 2c { + reg = <0x2c>; + compatible = "i2c-eeprom"; + emul { + compatible = "sandbox,i2c-eeprom"; + sandbox,filename = "i2c.bin"; + sandbox,size = <128>; + }; + }; + }; + spi at 0 { #address-cells = <1>; #size-cells = <0>;
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 10/12 dm: WIP: EEPROM driver
In reply to Simon GlassThere seem to be a few EEPROM drivers around - perhaps we should have a single standard one?
This is little more than a placeholder at present.
---
drivers/misc/Makefile | 1 + drivers/misc/i2c_eeprom.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/i2c_eeprom.h | 19 ++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 drivers/misc/i2c_eeprom.c create mode 100644 include/i2c_eeprom.h
drivers/misc/Makefile +1 -0
@@ -15,6 +15,7 @@ obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o obj-$(CONFIG_FSL_IIM) += fsl_iim.o obj-$(CONFIG_GPIO_LED) += gpio_led.o +obj-$(CONFIG_I2C_EEPROM) += i2c_eeprom.o obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
drivers/misc/i2c_eeprom.c new file +51 -0
51 lines not on this page · raw message
include/dm/uclass-id.h +1 -0
@@ -30,6 +30,7 @@ enum uclass_id {UCLASS_SPI_FLASH ,/* SPI flash */ UCLASS_CROS_EC ,/* Chrome OS EC */ UCLASS_I2C ,/* I2C bus */ +UCLASS_I2C_EEPROM ,/* I2C EEPROM device */ UCLASS_COUNT , UCLASS_INVALID = -1,
include/i2c_eeprom.h new file +19 -0
@@ -0,0 +1,19 @@ +/* +* Copyright (c) 2014 Google, Inc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __I2C_EEPROM +#define __I2C_EEPROM + +struct i2c_eeprom_ops { +int (*read)(struct udevice *dev,int offset,uint8_t *buf,int size); +int (*write)(struct udevice *dev,int offset,const uint8_t *buf, +int size); +}; + +struct i2c_eeprom { +}; + +#endif
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 11/12 dm: i2c: Add tests for I2C
In reply to Simon GlassAdd some basic tests to check that the system works as expected.
---
test/dm/Makefile | 1 + test/dm/i2c.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/dm/test.dts | 17 ++++++++++ 3 files changed, 118 insertions(+) create mode 100644 test/dm/i2c.c
test/dm/Makefile +1 -0
@@ -20,4 +20,5 @@ ifneq ($(CONFIG_SANDBOX),) obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_SPI) += spi.o obj-$(CONFIG_DM_SPI_FLASH) += sf.o +obj-$(CONFIG_DM_I2C) += i2c.o endif
test/dm/i2c.c new file +100 -0
100 lines not on this page · raw message
test/dm/test.dts +17 -0
@@ -93,6 +93,23 @@ num-gpios = <10>; }; + i2c at 0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + compatible = "sandbox,i2c"; + clock-frequency = <100000>; + eeprom at 2c { + reg = <0x2c>; + compatible = "i2c-eeprom"; + emul { + compatible = "sandbox,i2c-eeprom"; + sandbox,filename = "i2c.bin"; + sandbox,size = <128>; + }; + }; + }; + spi at 0 { #address-cells = <1>; #size-cells = <0>;
Signature · 1 line
2.1.0.rc2.206.gedb03e5
RFC PATCH 12/12 dm: i2c: tegra: Convert to driver model for I2C for seaboard
In reply to Simon GlassThis converts seaboard over to use driver model for I2C. This is so far untested and only useful for broad comments / review. To complete this, trimslice and whistler will also need conversion.
---
arch/arm/cpu/tegra20-common/pmu.c | 21 +- arch/arm/include/asm/arch-tegra/tegra_i2c.h | 2 +- board/nvidia/common/board.c | 4 - drivers/i2c/tegra_i2c.c | 313 ++++++++++------------------ drivers/power/tps6586x.c | 27 +-- include/configs/cardhu.h | 2 - include/configs/colibri_t30.h | 2 - include/configs/seaboard.h | 3 - include/configs/tegra-common.h | 1 + include/configs/tegra20-common.h | 3 - include/tps6586x.h | 2 +- 11 files changed, 140 insertions(+), 240 deletions(-)
arch/arm/cpu/tegra20-common/pmu.c +16 -5
@@ -6,6 +6,7 @@*/ #include <common.h> +#include <i2c.h> #include <tps6586x.h> #include <asm/io.h> #include <asm/arch/tegra.h>
@@ -23,9 +24,13 @@#define VDD_TRANSITION_STEP 0x06/* 150mv */ #define VDD_TRANSITION_RATE 0x06/* 3.52mv/us */ +#define PMI_I2C_ADDRESS 0x34/* chip requires this address */ +int pmu_set_nominal (void ) { -int core, cpu, bus; +struct udevice *bus, *dev; +int core, cpu; +int ret;/* by default, the table has been filled with T25 settings */ switch (tegra_get_chip_sku ()) {
@@ -42,12 +47,18 @@ int pmu_set_nominal(void)return -1 ; } - bus =tegra_i2c_get_dvc_bus_num (); -if (bus ==-1 ) { + ret =tegra_i2c_get_dvc_bus (&bus); +if (ret) {debug ("%s: Cannot find DVC I2C bus\n" , __func__); -return -1 ; +return ret; } -tps6586x_init (bus); + ret =i2c_get_chip (bus,PMI_I2C_ADDRESS , &dev); +if (ret) { +debug ("%s: Cannot find DVC I2C chip\n" , __func__); +return ret; + } + +tps6586x_init (dev);tps6586x_set_pwm_mode (TPS6586X_PWM_SM1 );return tps6586x_adjust_sm0_sm1 (core, cpu,VDD_TRANSITION_STEP ,VDD_TRANSITION_RATE ,VDD_RELATION );
arch/arm/include/asm/arch-tegra/tegra_i2c.h +1 -1
@@ -167,6 +167,6 @@ struct i2c_ctlr {* * @return number of bus, or -1 if there is no DVC active */ -int tegra_i2c_get_dvc_bus_num (void ); +int tegra_i2c_get_dvc_bus (struct udevice **busp);#endif /* _TEGRA_I2C_H_ */
board/nvidia/common/board.c +0 -4
@@ -132,10 +132,6 @@ int board_init(void)power_det_init ();#ifdef CONFIG_SYS_I2C_TEGRA -#ifndef CONFIG_SYS_I2C_INIT_BOARD -#error "You must define CONFIG_SYS_I2C_INIT_BOARD to use i2c on Nvidia boards" -#endif -i2c_init_board ();# ifdef CONFIG_TEGRA_PMU if (pmu_set_nominal ())debug ("Failed to select nominal voltages\n" );
drivers/i2c/tegra_i2c.c +114 -199
489 lines not on this page · raw message
drivers/power/tps6586x.c +7 -20
@@ -10,9 +10,7 @@#include <asm/io.h> #include <i2c.h> -static int bus_num;/* I2C bus we are on */ -#define I2C_ADDRESS 0x34/* chip requires this address */ -static char inited;/* 1 if we have been inited */ +static struct udevice *tps6586x_dev;enum {/* Registers that we access */
@@ -37,13 +35,9 @@ static int tps6586x_read(int reg)int i;uchar data;int retval =-1 ; -int old_bus_num; - - old_bus_num =i2c_get_bus_num (); -i2c_set_bus_num (bus_num);for (i =0 ; i <MAX_I2C_RETRY ; ++i) { -if (!i2c_read (I2C_ADDRESS , reg,1 , &data,1 )) { +if (!i2c_read (tps6586x_dev, reg, &data,1 )) { retval = (int )data; goto exit; }
@@ -53,7 +47,6 @@ static int tps6586x_read(int reg) } exit: -i2c_set_bus_num (old_bus_num);debug ("pmu_read %x=%x\n" , reg, retval);if (retval <0 ) debug("%s: failed to read register %#x: %d\n", __func__, reg,
@@ -65,13 +58,9 @@ static int tps6586x_write(int reg, uchar *data, uint len) {int i;int retval =-1 ; -int old_bus_num; - - old_bus_num =i2c_get_bus_num (); -i2c_set_bus_num (bus_num);for (i =0 ; i <MAX_I2C_RETRY ; ++i) { -if (!i2c_write (I2C_ADDRESS , reg,1 , data, len)) { +if (!i2c_write (tps6586x_dev, reg, data, len)) { retval =0 ; goto exit; }
@@ -81,7 +70,6 @@ static int tps6586x_write(int reg, uchar *data, uint len) } exit: -i2c_set_bus_num (old_bus_num);debug ("pmu_write %x=%x: " , reg, retval);for (i =0 ; i < len; i++)debug ("%x " , data[i]);
@@ -163,7 +151,7 @@ int tps6586x_set_pwm_mode(int mask)uchar val;int ret; -assert (inited); +assert (tps6586x_dev); ret =tps6586x_read (PFM_MODE );if (ret !=-1 ) { val = (uchar )ret;
@@ -184,7 +172,7 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate,int sm0, sm1;int bad; -assert (inited); +assert (tps6586x_dev);/* get current voltage settings */ if (read_voltages (&sm0, &sm1)) {
@@ -255,10 +243,9 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate,return bad ?-1 :0 ; } -int tps6586x_init (int bus) +int tps6586x_init (struct udevice *dev) { - bus_num = bus; - inited =1 ; + tps6586x_dev = dev;return 0 ; }
include/configs/cardhu.h +0 -2
@@ -45,8 +45,6 @@#define CONFIG_SYS_I2C_TEGRA #define CONFIG_SYS_I2C_INIT_BOARD #define CONFIG_I2C_MULTI_BUS -#define CONFIG_SYS_MAX_I2C_BUS TEGRA_I2C_NUM_CONTROLLERS -#define CONFIG_SYS_I2C_SPEED 100000#define CONFIG_CMD_I2C #define CONFIG_SYS_I2C
include/configs/colibri_t30.h +0 -2
@@ -27,9 +27,7 @@/* I2C */ #define CONFIG_SYS_I2C_TEGRA #define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000#define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC
include/configs/seaboard.h +0 -3
@@ -37,10 +37,7 @@/* I2C */ #define CONFIG_SYS_I2C_TEGRA -#define CONFIG_SYS_I2C_INIT_BOARD -#define CONFIG_SYS_I2C_SPEED 100000#define CONFIG_CMD_I2C -#define CONFIG_SYS_I2C /* SD/MMC */ #define CONFIG_MMC
include/configs/tegra-common.h +1 -0
@@ -26,6 +26,7 @@#endif #define CONFIG_DM_SPI #define CONFIG_DM_SPI_FLASH +#define CONFIG_DM_I2C #define CONFIG_SYS_TIMER_RATE 1000000#define CONFIG_SYS_TIMER_COUNTER NV_PA_TMRUS_BASE
include/configs/tegra20-common.h +0 -3
@@ -97,9 +97,6 @@#define CONFIG_EHCI_IS_TDI #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 -/* Total I2C ports on Tegra20 */ -#define TEGRA_I2C_NUM_CONTROLLERS 4 -#define CONFIG_SYS_NAND_SELF_INIT #define CONFIG_SYS_NAND_ONFI_DETECTION
include/tps6586x.h +1 -1
@@ -47,6 +47,6 @@ int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate,* @param bus I2C bus number containing the TPS6586X chip * @return 0 (always succeeds) */ -int tps6586x_init (int bus); +int tps6586x_init (struct udevice *bus);#endif /* _TPS6586X_H_ */
Signature · 1 line
2.1.0.rc2.206.gedb03e5
cover RFC: dm: Add I2C support
In reply to Simon GlassQuoted 32 lines · Simon Glass
(Note this is RFC since the uclass interface needs discussion and also because only sandbox is implemented so far. But I thought it best to get this out there as soon as I wrote it as it may influence the PMIC library, etc.)
This series is an initial attempt to add I2C support to driver model. It has become apparent that this is a high priority as it is widely used. It follows along to some extent from the SPI conversion.
Several changes are made from the original I2C implementations.
Firstly It is not necessary to specify the chip address with every call, since each chip knows its own address - it is stored in struct
dm_i2c_chipwhich is attached to each chip on the I2C bus. However, this information *is* passed to the driver since I presume most drivers need it and it would be cumbersome to look up in every call.Secondly there is no concept of a 'current' I2C bus so all associated logic is removed. With driver model
i2c_set_bus_num()andi2c_get_bus_num()are not available. Since the chip device specifies both the bus and the chip address, there is no need for this concept. It also causes problems when one driver changes the current bus and forgets to change it back.Thirdly initialisation is handled by driver model's normal
probe()method on each device so there should be no need fori2c_init_all(),i2c_init(),i2c_init_board(),i2c_board_late_init()andboard_i2c_init().I2C muxes are not yet supported. To support these we will need to maintain state of the current mux settings to avoid resetting every mux every time. Probably we need to add a sandbox I2C mux driver to permit testing of this. This can probably be done later.
Quoted 7 lines
Platform data is not yet supported either, only device tree. The
U_BOOT_I2C_MKENT_COMPLETE()andU_BOOT_I2C_ADAP_COMPLETE()macros are not used. Also structi2c_adapteris not defined anymore. This will need to be addressed, perhaps as part of converting over a board that does not use device tree.This series is available at u-boot-dm/i2c-working.
Nothing jumped out at me. Heiko?
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20141024/ede72dd0/attachment-0001.pgp>
cover RFC: dm: Add I2C support
Hello Tom,
Am 24.10.2014 17:03, schrieb Tom Rini:
Quoted 40 lines · Simon Glass
Quoted 39 lines
(Note this is RFC since the uclass interface needs discussion and also because only sandbox is implemented so far. But I thought it best to get this out there as soon as I wrote it as it may influence the PMIC library, etc.)
This series is an initial attempt to add I2C support to driver model. It has become apparent that this is a high priority as it is widely used. It follows along to some extent from the SPI conversion.
Several changes are made from the original I2C implementations.
Firstly It is not necessary to specify the chip address with every call, since each chip knows its own address - it is stored in struct
dm_i2c_chipwhich is attached to each chip on the I2C bus. However, this information *is* passed to the driver since I presume most drivers need it and it would be cumbersome to look up in every call.Secondly there is no concept of a 'current' I2C bus so all associated logic is removed. With driver model
i2c_set_bus_num()andi2c_get_bus_num()are not available. Since the chip device specifies both the bus and the chip address, there is no need for this concept. It also causes problems when one driver changes the current bus and forgets to change it back.Thirdly initialisation is handled by driver model's normal
probe()method on each device so there should be no need fori2c_init_all(),i2c_init(),i2c_init_board(),i2c_board_late_init()andboard_i2c_init().I2C muxes are not yet supported. To support these we will need to maintain state of the current mux settings to avoid resetting every mux every time. Probably we need to add a sandbox I2C mux driver to permit testing of this. This can probably be done later.
Platform data is not yet supported either, only device tree. The
U_BOOT_I2C_MKENT_COMPLETE()andU_BOOT_I2C_ADAP_COMPLETE()macros are not used. Also structi2c_adapteris not defined anymore. This will need to be addressed, perhaps as part of converting over a board that does not use device tree.
Quoted 3 lines
Quoted 1 line
This series is available at u-boot-dm/i2c-working.
Nothing jumped out at me. Heiko?
Looking in this patches soon... sorry for the delay.
bye,
Heiko
Signature · 2 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
cover RFC: dm: Add I2C support
In reply to Simon GlassHello Simon,
sorry for the long delay...
Am 13.10.2014 07:39, schrieb Simon Glass:
Quoted 23 lines
(Note this is RFC since the uclass interface needs discussion and also because only sandbox is implemented so far. But I thought it best to get this out there as soon as I wrote it as it may influence the PMIC library, etc.)
This series is an initial attempt to add I2C support to driver model. It has become apparent that this is a high priority as it is widely used. It follows along to some extent from the SPI conversion.
Several changes are made from the original I2C implementations.
Firstly It is not necessary to specify the chip address with every call, since each chip knows its own address - it is stored in struct
dm_i2c_chipwhich is attached to each chip on the I2C bus. However, this information *is* passed to the driver since I presume most drivers need it and it would be cumbersome to look up in every call.Secondly there is no concept of a 'current' I2C bus so all associated logic is removed. With driver model
i2c_set_bus_num()andi2c_get_bus_num()are not available. Since the chip device specifies both the bus and the chip address, there is no need for this concept. It also causes problems when one driver changes the current bus and forgets to change it back.
Quoted 3 lines
Thirdly initialisation is handled by driver model's normal
probe()method on each device so there should be no need fori2c_init_all(),i2c_init(),i2c_init_board(),i2c_board_late_init()andboard_i2c_init().
Great!
Quoted 4 lines
I2C muxes are not yet supported. To support these we will need to maintain state of the current mux settings to avoid resetting every mux every time. Probably we need to add a sandbox I2C mux driver to permit testing of this. This can probably be done later.
Currently only the keymile boards really use i2c muxes, so I am fine with doing this in a second step.
Quoted 5 lines
Platform data is not yet supported either, only device tree. The
U_BOOT_I2C_MKENT_COMPLETE()andU_BOOT_I2C_ADAP_COMPLETE()macros are not used. Also structi2c_adapteris not defined anymore. This will need to be addressed, perhaps as part of converting over a board that does not use device tree.
Ok for this in the first step... The question raised if we only would support Device tree with DM ... so maybe we do not need to do this step.
I am not really sure, if we should really support Device Tree only with DM, because:
- do all archs switch to Device Tree in the near future?
- in SPL we have really on some SoCs small memory (like I just work on some AT91 boards which have 4k only!) To get DM with Device Tree into 4k is a big challenge ... so in my opinion, it would be good to have the possibility of Platform data ... so we prevent to make dirty hacks for the SPL case (I hope) ...
Quoted 1 line
This series is available at u-boot-dm/i2c-working.
Thanks for your great work.
I looked through your patchset and have no real objection against it ... To the "i2c deblocking" subject ... we should add at least the "deblock()" in "struct dm_i2c_ops" and call it "do_i2c_reset" if defined ... beside of this, you can add my
to the hole series.
bye,
Heiko
Signature · 2 lines
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
cover RFC: dm: Add I2C support
Hi Heiko,
Quoted 74 lines · Heiko Schocher
Hello Simon,
sorry for the long delay...
Am 13.10.2014 07:39, schrieb Simon Glass:
Quoted 26 lines
(Note this is RFC since the uclass interface needs discussion and also because only sandbox is implemented so far. But I thought it best to get this out there as soon as I wrote it as it may influence the PMIC library, etc.)
This series is an initial attempt to add I2C support to driver model. It has become apparent that this is a high priority as it is widely used. It follows along to some extent from the SPI conversion.
Several changes are made from the original I2C implementations.
Firstly It is not necessary to specify the chip address with every call, since each chip knows its own address - it is stored in struct
dm_i2c_chipwhich is attached to each chip on the I2C bus. However, this information *is* passed to the driver since I presume most drivers need it and it would
be cumbersome to look up in every call.Secondly there is no concept of a 'current' I2C bus so all associated logic
is removed. With driver modeli2c_set_bus_num()andi2c_get_bus_num()are not available. Since the chip device specifies both the bus and the chip address, there is no need for this concept. It also causes problems when one driver changes the current bus and forgets to change it back.Quoted 3 lines
Thirdly initialisation is handled by driver model's normal
probe()method on each device so there should be no need fori2c_init_all(),i2c_init(),i2c_init_board(),i2c_board_late_init()andboard_i2c_init().Great!
Quoted 5 lines
I2C muxes are not yet supported. To support these we will need to maintain state of the current mux settings to avoid resetting every mux every time. Probably we need to add a sandbox I2C mux driver to permit testing of this.
This can probably be done later.Currently only the keymile boards really use i2c muxes, so I am fine with doing this in a second step.
Quoted 5 lines
Platform data is not yet supported either, only device tree. The
U_BOOT_I2C_MKENT_COMPLETE()andU_BOOT_I2C_ADAP_COMPLETE()macros are not used. Also structi2c_adapteris not defined anymore. This will need to be addressed, perhaps as part of converting over a board that does not use device tree.Ok for this in the first step... The question raised if we only would support Device tree with DM ... so maybe we do not need to do this step.
I am not really sure, if we should really support Device Tree only with DM, because:
- do all archs switch to Device Tree in the near future?
- in SPL we have really on some SoCs small memory (like I just work on some AT91 boards which have 4k only!) To get DM with Device Tree into 4k is a big challenge ... so in my opinion, it would be good to have the possibility of Platform data ... so we prevent to make dirty hacks for the SPL case (I hope) ...
Quoted 1 line
This series is available at u-boot-dm/i2c-working.
Thanks for your great work.
Quoted 8 lines
I looked through your patchset and have no real objection against it ... To the "i2c deblocking" subject ... we should add at least the "
deblock()" in "structdm_i2c_ops" and call it "do_i2c_reset" if defined ... beside of this, you can add myAcked-by Heiko Schocher <[email protected]>to the hole series.
Thanks for reviewing this. I have added the deblock() method and also the generic I2C support (allows you to use a device on the command line without it having a proper driver). There are a few changes so if you have time to take another look I will definitely add your Acked-by.
Regards,
Simon