diff options
| -rw-r--r-- | common/spl/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/Makefile | 1 | ||||
| -rw-r--r-- | drivers/core/device.c | 7 | ||||
| -rw-r--r-- | drivers/i2c/imx_lpi2c.c | 47 | ||||
| -rw-r--r-- | drivers/i2c/muxes/pca954x.c | 9 | ||||
| -rw-r--r-- | drivers/power/domain/Makefile | 2 | ||||
| -rw-r--r-- | include/imx_lpi2c.h | 3 | ||||
| -rw-r--r-- | include/power-domain.h | 29 | ||||
| -rw-r--r-- | test/dm/power-domain.c | 2 | 
9 files changed, 100 insertions, 9 deletions
| diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 0be8ff0d87d..0ad1e049a92 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -609,6 +609,15 @@ config SPL_POWER_SUPPORT  	  in drivers/power, drivers/power/pmic and drivers/power/regulator  	  as part of an SPL build. +config SPL_POWER_DOMAIN +	bool "Support power domain drivers" +	help +	  Enable support for power domain control in SPL. Many SoCs allow +	  power to be applied to or removed from portions of the SoC (power +	  domains). This may be used to save power. This API provides the +	  means to control such power management hardware. This enables +	  the drivers in drivers/power/domain as part of a SPL build. +  config SPL_RAM_SUPPORT  	bool "Support booting from RAM"  	default y if MICROBLAZE || ARCH_SOCFPGA || TEGRA || ARCH_ZYNQ diff --git a/drivers/Makefile b/drivers/Makefile index 276e5ee4d7e..d53208540ea 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_ARMADA_XP) += ddr/marvell/axp/  obj-$(CONFIG_ALTERA_SDRAM) += ddr/altera/  obj-$(CONFIG_SPL_POWER_SUPPORT) += power/ power/pmic/  obj-$(CONFIG_SPL_POWER_SUPPORT) += power/regulator/ +obj-$(CONFIG_SPL_POWER_DOMAIN) += power/domain/  obj-$(CONFIG_SPL_DM_RESET) += reset/  obj-$(CONFIG_SPL_MTD_SUPPORT) += mtd/  obj-$(CONFIG_SPL_ONENAND_SUPPORT) += mtd/onenand/ diff --git a/drivers/core/device.c b/drivers/core/device.c index d5f5fc31b03..207d566b71d 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -26,6 +26,7 @@  #include <dm/util.h>  #include <linux/err.h>  #include <linux/list.h> +#include <power-domain.h>  DECLARE_GLOBAL_DATA_PTR; @@ -304,6 +305,7 @@ static void *alloc_priv(int size, uint flags)  int device_probe(struct udevice *dev)  { +	struct power_domain pd;  	const struct driver *drv;  	int size = 0;  	int ret; @@ -383,6 +385,11 @@ int device_probe(struct udevice *dev)  	if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)  		pinctrl_select_state(dev, "default"); +	if (dev->parent && device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) { +		if (!power_domain_get(dev, &pd)) +			power_domain_on(&pd); +	} +  	ret = uclass_pre_probe_device(dev);  	if (ret)  		goto fail; diff --git a/drivers/i2c/imx_lpi2c.c b/drivers/i2c/imx_lpi2c.c index ff07ca34aac..6c343072fb2 100644 --- a/drivers/i2c/imx_lpi2c.c +++ b/drivers/i2c/imx_lpi2c.c @@ -261,8 +261,14 @@ static int bus_i2c_write(struct udevice *bus, u32 chip, u8 *buf, int len)  } +u32 __weak imx_get_i2cclk(u32 i2c_num) +{ +	return 0; +} +  static int bus_i2c_set_bus_speed(struct udevice *bus, int speed)  { +	struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);  	struct imx_lpi2c_reg *regs;  	u32 val;  	u32 preescale = 0, best_pre = 0, clkhi = 0; @@ -273,9 +279,18 @@ static int bus_i2c_set_bus_speed(struct udevice *bus, int speed)  	int i;  	regs = (struct imx_lpi2c_reg *)devfdt_get_addr(bus); -	clock_rate = imx_get_i2cclk(bus->seq); -	if (!clock_rate) -		return -EPERM; + +	if (IS_ENABLED(CONFIG_CLK)) { +		clock_rate = clk_get_rate(&i2c_bus->per_clk); +		if (clock_rate <= 0) { +			dev_err(bus, "Failed to get i2c clk: %d\n", clock_rate); +			return clock_rate; +		} +	} else { +		clock_rate = imx_get_i2cclk(bus->seq); +		if (!clock_rate) +			return -EPERM; +	}  	mode = (readl(®s->mcr) & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT;  	/* disable master mode */ @@ -417,6 +432,11 @@ static int imx_lpi2c_set_bus_speed(struct udevice *bus, unsigned int speed)  	return bus_i2c_set_bus_speed(bus, speed);  } +__weak int enable_i2c_clk(unsigned char enable, unsigned int i2c_num) +{ +	return 0; +} +  static int imx_lpi2c_probe(struct udevice *bus)  {  	struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus); @@ -440,10 +460,23 @@ static int imx_lpi2c_probe(struct udevice *bus)  		return ret;  	} -	/* To i.MX7ULP, only i2c4-7 can be handled by A7 core */ -	ret = enable_i2c_clk(1, bus->seq); -	if (ret < 0) -		return ret; +	if (IS_ENABLED(CONFIG_CLK)) { +		ret = clk_get_by_name(bus, "per", &i2c_bus->per_clk); +		if (ret) { +			dev_err(bus, "Failed to get per clk\n"); +			return ret; +		} +		ret = clk_enable(&i2c_bus->per_clk); +		if (ret) { +			dev_err(bus, "Failed to enable per clk\n"); +			return ret; +		} +	} else { +		/* To i.MX7ULP, only i2c4-7 can be handled by A7 core */ +		ret = enable_i2c_clk(1, bus->seq); +		if (ret < 0) +			return ret; +	}  	ret = bus_i2c_init(bus, 100000);  	if (ret < 0) diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c index 4debc039572..ab8b4000afb 100644 --- a/drivers/i2c/muxes/pca954x.c +++ b/drivers/i2c/muxes/pca954x.c @@ -17,7 +17,8 @@ DECLARE_GLOBAL_DATA_PTR;  enum pca_type {  	PCA9544,  	PCA9547, -	PCA9548 +	PCA9548, +	PCA9646  };  struct chip_desc { @@ -51,6 +52,11 @@ static const struct chip_desc chips[] = {  		.muxtype = pca954x_isswi,  		.width = 8,  	}, +	[PCA9646] = { +		.enable = 0x0, +		.muxtype = pca954x_isswi, +		.width = 4, +	},  };  static int pca954x_deselect(struct udevice *mux, struct udevice *bus, @@ -86,6 +92,7 @@ static const struct udevice_id pca954x_ids[] = {  	{ .compatible = "nxp,pca9544", .data = PCA9544 },  	{ .compatible = "nxp,pca9547", .data = PCA9547 },  	{ .compatible = "nxp,pca9548", .data = PCA9548 }, +	{ .compatible = "nxp,pca9646", .data = PCA9646 },  	{ }  }; diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index c7d76444020..020eee23782 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -2,7 +2,7 @@  #  # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_POWER_DOMAIN) += power-domain-uclass.o +obj-$(CONFIG_$(SPL_)POWER_DOMAIN) += power-domain-uclass.o  obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o  obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o  obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o diff --git a/include/imx_lpi2c.h b/include/imx_lpi2c.h index 3fbb40bdd1a..2700e5f8763 100644 --- a/include/imx_lpi2c.h +++ b/include/imx_lpi2c.h @@ -8,6 +8,8 @@  #ifndef __IMX_LPI2C_H__  #define __IMX_LPI2C_H__ +#include <clk.h> +  struct imx_lpi2c_bus {  	int index;  	ulong base; @@ -15,6 +17,7 @@ struct imx_lpi2c_bus {  	int speed;  	struct i2c_pads_info *pads_info;  	struct udevice *bus; +	struct clk per_clk;  };  struct imx_lpi2c_reg { diff --git a/include/power-domain.h b/include/power-domain.h index aba8c0f65c4..a558fbbdb21 100644 --- a/include/power-domain.h +++ b/include/power-domain.h @@ -87,7 +87,15 @@ struct power_domain {   * @power_domain	A pointer to a power domain struct to initialize.   * @return 0 if OK, or a negative error code.   */ +#if CONFIG_IS_ENABLED(POWER_DOMAIN)  int power_domain_get(struct udevice *dev, struct power_domain *power_domain); +#else +static inline +int power_domain_get(struct udevice *dev, struct power_domain *power_domain) +{ +	return -ENOSYS; +} +#endif  /**   * power_domain_free - Free a previously requested power domain. @@ -96,7 +104,14 @@ int power_domain_get(struct udevice *dev, struct power_domain *power_domain);   *		requested by power_domain_get().   * @return 0 if OK, or a negative error code.   */ +#if CONFIG_IS_ENABLED(POWER_DOMAIN)  int power_domain_free(struct power_domain *power_domain); +#else +static inline int power_domain_free(struct power_domain *power_domain) +{ +	return -ENOSYS; +} +#endif  /**   * power_domain_on - Enable power to a power domain. @@ -105,7 +120,14 @@ int power_domain_free(struct power_domain *power_domain);   *		requested by power_domain_get().   * @return 0 if OK, or a negative error code.   */ +#if CONFIG_IS_ENABLED(POWER_DOMAIN)  int power_domain_on(struct power_domain *power_domain); +#else +static inline int power_domain_on(struct power_domain *power_domain) +{ +	return -ENOSYS; +} +#endif  /**   * power_domain_off - Disable power ot a power domain. @@ -114,6 +136,13 @@ int power_domain_on(struct power_domain *power_domain);   *		requested by power_domain_get().   * @return 0 if OK, or a negative error code.   */ +#if CONFIG_IS_ENABLED(POWER_DOMAIN)  int power_domain_off(struct power_domain *power_domain); +#else +static inline int power_domain_off(struct power_domain *power_domain) +{ +	return -ENOSYS; +} +#endif  #endif diff --git a/test/dm/power-domain.c b/test/dm/power-domain.c index a1e1df2bb21..48318218a9e 100644 --- a/test/dm/power-domain.c +++ b/test/dm/power-domain.c @@ -26,6 +26,8 @@ static int dm_test_power_domain(struct unit_test_state *uts)  	ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "power-domain-test",  					      &dev_test)); +	ut_asserteq(1, sandbox_power_domain_query(dev_power_domain, +						  TEST_POWER_DOMAIN));  	ut_assertok(sandbox_power_domain_test_get(dev_test));  	ut_assertok(sandbox_power_domain_test_on(dev_test)); | 
