|
|
@@ -1,570 +0,0 @@
|
|
|
---- a/drivers/regulator/Kconfig
|
|
|
-+++ b/drivers/regulator/Kconfig
|
|
|
-@@ -462,6 +462,14 @@ config REGULATOR_MT6397
|
|
|
- This driver supports the control of different power rails of device
|
|
|
- through regulator interface.
|
|
|
-
|
|
|
-+config REGULATOR_MXS
|
|
|
-+ tristate "Freescale MXS on-chip regulators"
|
|
|
-+ depends on (MXS_POWER || COMPILE_TEST)
|
|
|
-+ help
|
|
|
-+ Say y here to support Freescale MXS on-chip regulators.
|
|
|
-+ It is recommended that this option be enabled on i.MX23,
|
|
|
-+ i.MX28 platform.
|
|
|
-+
|
|
|
- config REGULATOR_PALMAS
|
|
|
- tristate "TI Palmas PMIC Regulators"
|
|
|
- depends on MFD_PALMAS
|
|
|
---- a/drivers/regulator/Makefile
|
|
|
-+++ b/drivers/regulator/Makefile
|
|
|
-@@ -61,6 +61,7 @@ obj-$(CONFIG_REGULATOR_MC13892) += mc138
|
|
|
- obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
|
|
|
- obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
|
|
|
- obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
|
|
|
-+obj-$(CONFIG_REGULATOR_MXS) += mxs-regulator.o
|
|
|
- obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
|
|
|
- obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
|
|
|
- obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
|
|
|
---- /dev/null
|
|
|
-+++ b/drivers/regulator/mxs-regulator.c
|
|
|
-@@ -0,0 +1,540 @@
|
|
|
-+/*
|
|
|
-+ * Freescale MXS on-chip regulators
|
|
|
-+ *
|
|
|
-+ * Embedded Alley Solutions, Inc <[email protected]>
|
|
|
-+ *
|
|
|
-+ * Copyright (C) 2014 Stefan Wahren
|
|
|
-+ * Copyright (C) 2010 Freescale Semiconductor, Inc.
|
|
|
-+ * Copyright (C) 2008 Embedded Alley Solutions, Inc All Rights Reserved.
|
|
|
-+ *
|
|
|
-+ * Inspired by imx-bootlets
|
|
|
-+ */
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * The code contained herein is licensed under the GNU General Public
|
|
|
-+ * License. You may obtain a copy of the GNU General Public License
|
|
|
-+ * Version 2 or later at the following locations:
|
|
|
-+ *
|
|
|
-+ * http://www.opensource.org/licenses/gpl-license.html
|
|
|
-+ * http://www.gnu.org/copyleft/gpl.html
|
|
|
-+ */
|
|
|
-+
|
|
|
-+#include <linux/delay.h>
|
|
|
-+#include <linux/device.h>
|
|
|
-+#include <linux/err.h>
|
|
|
-+#include <linux/kernel.h>
|
|
|
-+#include <linux/mfd/syscon.h>
|
|
|
-+#include <linux/module.h>
|
|
|
-+#include <linux/of.h>
|
|
|
-+#include <linux/of_device.h>
|
|
|
-+#include <linux/platform_device.h>
|
|
|
-+#include <linux/regmap.h>
|
|
|
-+#include <linux/regulator/driver.h>
|
|
|
-+#include <linux/regulator/machine.h>
|
|
|
-+#include <linux/regulator/of_regulator.h>
|
|
|
-+#include <linux/slab.h>
|
|
|
-+
|
|
|
-+/* Powered by linear regulator. DCDC output is gated off and
|
|
|
-+ the linreg output is equal to the target. */
|
|
|
-+#define HW_POWER_LINREG_DCDC_OFF 1
|
|
|
-+
|
|
|
-+/* Powered by linear regulator. DCDC output is not gated off
|
|
|
-+ and is ready for the automatic hardware transistion after a 5V
|
|
|
-+ event. The converters are not enabled when 5V is present. LinReg output
|
|
|
-+ is 25mV below target. */
|
|
|
-+#define HW_POWER_LINREG_DCDC_READY 2
|
|
|
-+
|
|
|
-+/* Powered by DCDC converter and the LinReg is on. LinReg output
|
|
|
-+ is 25mV below target. */
|
|
|
-+#define HW_POWER_DCDC_LINREG_ON 3
|
|
|
-+
|
|
|
-+/* Powered by DCDC converter and the LinReg is off. LinReg output
|
|
|
-+ is 25mV below target. */
|
|
|
-+#define HW_POWER_DCDC_LINREG_OFF 4
|
|
|
-+
|
|
|
-+/* Powered by DCDC converter and the LinReg is ready for the
|
|
|
-+ automatic hardware transfer. The LinReg output is not enabled and
|
|
|
-+ depends on the 5V presence to enable the LinRegs. LinReg offset is 25mV
|
|
|
-+ below target. */
|
|
|
-+#define HW_POWER_DCDC_LINREG_READY 5
|
|
|
-+
|
|
|
-+/* Powered by an external source when 5V is present. This does not
|
|
|
-+ necessarily mean the external source is powered by 5V,but the chip needs
|
|
|
-+ to be aware that 5V is present. */
|
|
|
-+#define HW_POWER_EXTERNAL_SOURCE_5V 6
|
|
|
-+
|
|
|
-+/* Powered by an external source when 5V is not present.This doesn't
|
|
|
-+ necessarily mean the external source is powered by the battery, but the
|
|
|
-+ chip needs to be aware that the battery is present */
|
|
|
-+#define HW_POWER_EXTERNAL_SOURCE_BATTERY 7
|
|
|
-+
|
|
|
-+/* Unknown configuration. This is an error. */
|
|
|
-+#define HW_POWER_UNKNOWN_SOURCE 8
|
|
|
-+
|
|
|
-+/* TODO: Move power register offsets into header file */
|
|
|
-+#define HW_POWER_5VCTRL 0x00000010
|
|
|
-+#define HW_POWER_VDDDCTRL 0x00000040
|
|
|
-+#define HW_POWER_VDDACTRL 0x00000050
|
|
|
-+#define HW_POWER_VDDIOCTRL 0x00000060
|
|
|
-+#define HW_POWER_MISC 0x00000090
|
|
|
-+#define HW_POWER_STS 0x000000c0
|
|
|
-+
|
|
|
-+#define BM_POWER_STS_VBUSVALID0_STATUS BIT(15)
|
|
|
-+#define BM_POWER_STS_DC_OK BIT(9)
|
|
|
-+
|
|
|
-+#define BM_POWER_5VCTRL_ILIMIT_EQ_ZERO BIT(2)
|
|
|
-+#define BM_POWER_5VCTRL_ENABLE_DCDC BIT(0)
|
|
|
-+
|
|
|
-+#define BM_POWER_LINREG_OFFSET_DCDC_MODE BIT(1)
|
|
|
-+
|
|
|
-+#define SHIFT_FREQSEL 4
|
|
|
-+
|
|
|
-+#define BM_POWER_MISC_FREQSEL (7 << SHIFT_FREQSEL)
|
|
|
-+
|
|
|
-+/* Recommended DC-DC clock source values */
|
|
|
-+#define HW_POWER_MISC_FREQSEL_20000_KHZ 1
|
|
|
-+#define HW_POWER_MISC_FREQSEL_24000_KHZ 2
|
|
|
-+#define HW_POWER_MISC_FREQSEL_19200_KHZ 3
|
|
|
-+
|
|
|
-+#define HW_POWER_MISC_SEL_PLLCLK BIT(0)
|
|
|
-+
|
|
|
-+/* Regulator IDs */
|
|
|
-+#define MXS_DCDC 1
|
|
|
-+#define MXS_VDDIO 2
|
|
|
-+#define MXS_VDDA 3
|
|
|
-+#define MXS_VDDD 4
|
|
|
-+
|
|
|
-+struct mxs_reg_info {
|
|
|
-+ /* regulator descriptor */
|
|
|
-+ struct regulator_desc desc;
|
|
|
-+
|
|
|
-+ /* regulator control register */
|
|
|
-+ int ctrl_reg;
|
|
|
-+
|
|
|
-+ /* disable DC-DC output */
|
|
|
-+ unsigned int disable_fet_mask;
|
|
|
-+
|
|
|
-+ /* steps between linreg output and DC-DC target */
|
|
|
-+ unsigned int linreg_offset_mask;
|
|
|
-+ u8 linreg_offset_shift;
|
|
|
-+
|
|
|
-+ /* function which determine power source */
|
|
|
-+ u8 (*get_power_source)(struct regulator_dev *);
|
|
|
-+};
|
|
|
-+
|
|
|
-+static inline u8 get_linreg_offset(struct mxs_reg_info *ldo, u32 regs)
|
|
|
-+{
|
|
|
-+ return (regs & ldo->linreg_offset_mask) >> ldo->linreg_offset_shift;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static u8 get_vddio_power_source(struct regulator_dev *reg)
|
|
|
-+{
|
|
|
-+ struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
|
|
|
-+ u32 v5ctrl, status, base;
|
|
|
-+ u8 offset;
|
|
|
-+
|
|
|
-+ if (regmap_read(reg->regmap, HW_POWER_5VCTRL, &v5ctrl))
|
|
|
-+ return HW_POWER_UNKNOWN_SOURCE;
|
|
|
-+
|
|
|
-+ if (regmap_read(reg->regmap, HW_POWER_STS, &status))
|
|
|
-+ return HW_POWER_UNKNOWN_SOURCE;
|
|
|
-+
|
|
|
-+ if (regmap_read(reg->regmap, ldo->ctrl_reg, &base))
|
|
|
-+ return HW_POWER_UNKNOWN_SOURCE;
|
|
|
-+
|
|
|
-+ offset = get_linreg_offset(ldo, base);
|
|
|
-+
|
|
|
-+ /* If VBUS valid then 5 V power supply present */
|
|
|
-+ if (status & BM_POWER_STS_VBUSVALID0_STATUS) {
|
|
|
-+ /* Powered by Linreg, DC-DC is off */
|
|
|
-+ if ((base & ldo->disable_fet_mask) &&
|
|
|
-+ !(offset & BM_POWER_LINREG_OFFSET_DCDC_MODE)) {
|
|
|
-+ return HW_POWER_LINREG_DCDC_OFF;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (v5ctrl & BM_POWER_5VCTRL_ENABLE_DCDC) {
|
|
|
-+ /* Powered by DC-DC, Linreg is on */
|
|
|
-+ if (offset & BM_POWER_LINREG_OFFSET_DCDC_MODE)
|
|
|
-+ return HW_POWER_DCDC_LINREG_ON;
|
|
|
-+ } else {
|
|
|
-+ /* Powered by Linreg, DC-DC is off */
|
|
|
-+ if (!(offset & BM_POWER_LINREG_OFFSET_DCDC_MODE))
|
|
|
-+ return HW_POWER_LINREG_DCDC_OFF;
|
|
|
-+ }
|
|
|
-+ } else {
|
|
|
-+ /* Powered by DC-DC, Linreg is on */
|
|
|
-+ if (offset & BM_POWER_LINREG_OFFSET_DCDC_MODE)
|
|
|
-+ return HW_POWER_DCDC_LINREG_ON;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return HW_POWER_UNKNOWN_SOURCE;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static u8 get_vdda_vddd_power_source(struct regulator_dev *reg)
|
|
|
-+{
|
|
|
-+ struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
|
|
|
-+ struct regulator_desc *desc = &ldo->desc;
|
|
|
-+ u32 v5ctrl, status, base;
|
|
|
-+ u8 offset;
|
|
|
-+
|
|
|
-+ if (regmap_read(reg->regmap, HW_POWER_5VCTRL, &v5ctrl))
|
|
|
-+ return HW_POWER_UNKNOWN_SOURCE;
|
|
|
-+
|
|
|
-+ if (regmap_read(reg->regmap, HW_POWER_STS, &status))
|
|
|
-+ return HW_POWER_UNKNOWN_SOURCE;
|
|
|
-+
|
|
|
-+ if (regmap_read(reg->regmap, ldo->ctrl_reg, &base))
|
|
|
-+ return HW_POWER_UNKNOWN_SOURCE;
|
|
|
-+
|
|
|
-+ offset = get_linreg_offset(ldo, base);
|
|
|
-+
|
|
|
-+ /* DC-DC output is disabled */
|
|
|
-+ if (base & ldo->disable_fet_mask) {
|
|
|
-+ /* Powered by 5 V supply */
|
|
|
-+ if (status & BM_POWER_STS_VBUSVALID0_STATUS)
|
|
|
-+ return HW_POWER_EXTERNAL_SOURCE_5V;
|
|
|
-+
|
|
|
-+ /* Powered by Linreg, DC-DC is off */
|
|
|
-+ if (!(offset & BM_POWER_LINREG_OFFSET_DCDC_MODE))
|
|
|
-+ return HW_POWER_LINREG_DCDC_OFF;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* If VBUS valid then 5 V power supply present */
|
|
|
-+ if (status & BM_POWER_STS_VBUSVALID0_STATUS) {
|
|
|
-+ /* Powered by DC-DC, Linreg is on */
|
|
|
-+ if (v5ctrl & BM_POWER_5VCTRL_ENABLE_DCDC)
|
|
|
-+ return HW_POWER_DCDC_LINREG_ON;
|
|
|
-+
|
|
|
-+ /* Powered by Linreg, DC-DC is off */
|
|
|
-+ return HW_POWER_LINREG_DCDC_OFF;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* DC-DC is on */
|
|
|
-+ if (offset & BM_POWER_LINREG_OFFSET_DCDC_MODE) {
|
|
|
-+ /* Powered by DC-DC, Linreg is on */
|
|
|
-+ if (base & desc->enable_mask)
|
|
|
-+ return HW_POWER_DCDC_LINREG_ON;
|
|
|
-+
|
|
|
-+ /* Powered by DC-DC, Linreg is off */
|
|
|
-+ return HW_POWER_DCDC_LINREG_OFF;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return HW_POWER_UNKNOWN_SOURCE;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static int mxs_set_dcdc_freq(struct regulator_dev *reg, u32 hz)
|
|
|
-+{
|
|
|
-+ struct mxs_reg_info *dcdc = rdev_get_drvdata(reg);
|
|
|
-+ u32 val;
|
|
|
-+ int ret;
|
|
|
-+
|
|
|
-+ if (dcdc->desc.id != MXS_DCDC) {
|
|
|
-+ dev_warn(®->dev, "Setting switching freq is not supported\n");
|
|
|
-+ return -EINVAL;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ ret = regmap_read(reg->regmap, HW_POWER_MISC, &val);
|
|
|
-+ if (ret)
|
|
|
-+ return ret;
|
|
|
-+
|
|
|
-+ val &= ~BM_POWER_MISC_FREQSEL;
|
|
|
-+ val &= ~HW_POWER_MISC_SEL_PLLCLK;
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Select the PLL/PFD based frequency that the DC-DC converter uses.
|
|
|
-+ * The actual switching frequency driving the power inductor is
|
|
|
-+ * DCDC_CLK/16. Accept only values recommend by Freescale.
|
|
|
-+ */
|
|
|
-+ switch (hz) {
|
|
|
-+ case 1200000:
|
|
|
-+ val |= HW_POWER_MISC_FREQSEL_19200_KHZ << SHIFT_FREQSEL;
|
|
|
-+ break;
|
|
|
-+ case 1250000:
|
|
|
-+ val |= HW_POWER_MISC_FREQSEL_20000_KHZ << SHIFT_FREQSEL;
|
|
|
-+ break;
|
|
|
-+ case 1500000:
|
|
|
-+ val |= HW_POWER_MISC_FREQSEL_24000_KHZ << SHIFT_FREQSEL;
|
|
|
-+ break;
|
|
|
-+ default:
|
|
|
-+ dev_warn(®->dev, "Switching freq: %u Hz not supported\n",
|
|
|
-+ hz);
|
|
|
-+ return -EINVAL;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* First program FREQSEL */
|
|
|
-+ ret = regmap_write(reg->regmap, HW_POWER_MISC, val);
|
|
|
-+ if (ret)
|
|
|
-+ return ret;
|
|
|
-+
|
|
|
-+ /* then set PLL as clock for DC-DC converter */
|
|
|
-+ val |= HW_POWER_MISC_SEL_PLLCLK;
|
|
|
-+
|
|
|
-+ return regmap_write(reg->regmap, HW_POWER_MISC, val);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static int mxs_ldo_set_voltage_sel(struct regulator_dev *reg, unsigned sel)
|
|
|
-+{
|
|
|
-+ struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
|
|
|
-+ struct regulator_desc *desc = &ldo->desc;
|
|
|
-+ u32 status = 0;
|
|
|
-+ int timeout;
|
|
|
-+ int ret;
|
|
|
-+
|
|
|
-+ ret = regmap_update_bits(reg->regmap, desc->vsel_reg, desc->vsel_mask,
|
|
|
-+ sel);
|
|
|
-+ if (ret)
|
|
|
-+ return ret;
|
|
|
-+
|
|
|
-+ if (ldo->get_power_source) {
|
|
|
-+ switch (ldo->get_power_source(reg)) {
|
|
|
-+ case HW_POWER_LINREG_DCDC_OFF:
|
|
|
-+ case HW_POWER_LINREG_DCDC_READY:
|
|
|
-+ case HW_POWER_EXTERNAL_SOURCE_5V:
|
|
|
-+ /*
|
|
|
-+ * Since the DC-DC converter is off we can't
|
|
|
-+ * trigger on DC_OK. So wait at least 1 ms
|
|
|
-+ * for stabilization.
|
|
|
-+ */
|
|
|
-+ usleep_range(1000, 2000);
|
|
|
-+ return 0;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Make sure DC_OK has changed */
|
|
|
-+ usleep_range(15, 20);
|
|
|
-+
|
|
|
-+ for (timeout = 0; timeout < 20; timeout++) {
|
|
|
-+ ret = regmap_read(reg->regmap, HW_POWER_STS, &status);
|
|
|
-+
|
|
|
-+ if (ret)
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ /* DC-DC converter control loop has stabilized */
|
|
|
-+ if (status & BM_POWER_STS_DC_OK)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ udelay(1);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!ret)
|
|
|
-+ dev_warn_ratelimited(®->dev, "%s: timeout status=0x%08x\n",
|
|
|
-+ __func__, status);
|
|
|
-+
|
|
|
-+ msleep(20);
|
|
|
-+
|
|
|
-+ return -ETIMEDOUT;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static int mxs_ldo_is_enabled(struct regulator_dev *reg)
|
|
|
-+{
|
|
|
-+ struct mxs_reg_info *ldo = rdev_get_drvdata(reg);
|
|
|
-+
|
|
|
-+ if (ldo->get_power_source) {
|
|
|
-+ switch (ldo->get_power_source(reg)) {
|
|
|
-+ case HW_POWER_LINREG_DCDC_OFF:
|
|
|
-+ case HW_POWER_LINREG_DCDC_READY:
|
|
|
-+ case HW_POWER_DCDC_LINREG_ON:
|
|
|
-+ return 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static struct regulator_ops mxs_dcdc_ops = {
|
|
|
-+ .is_enabled = regulator_is_enabled_regmap,
|
|
|
-+};
|
|
|
-+
|
|
|
-+static struct regulator_ops mxs_ldo_ops = {
|
|
|
-+ .list_voltage = regulator_list_voltage_linear,
|
|
|
-+ .map_voltage = regulator_map_voltage_linear,
|
|
|
-+ .set_voltage_sel = mxs_ldo_set_voltage_sel,
|
|
|
-+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
|
-+ .is_enabled = mxs_ldo_is_enabled,
|
|
|
-+};
|
|
|
-+
|
|
|
-+static const struct mxs_reg_info mxs_info_dcdc = {
|
|
|
-+ .desc = {
|
|
|
-+ .name = "dcdc",
|
|
|
-+ .id = MXS_DCDC,
|
|
|
-+ .type = REGULATOR_VOLTAGE,
|
|
|
-+ .owner = THIS_MODULE,
|
|
|
-+ .ops = &mxs_dcdc_ops,
|
|
|
-+ .enable_reg = HW_POWER_STS,
|
|
|
-+ .enable_mask = (1 << 0),
|
|
|
-+ },
|
|
|
-+};
|
|
|
-+
|
|
|
-+static const struct mxs_reg_info imx23_info_vddio = {
|
|
|
-+ .desc = {
|
|
|
-+ .name = "vddio",
|
|
|
-+ .id = MXS_VDDIO,
|
|
|
-+ .type = REGULATOR_VOLTAGE,
|
|
|
-+ .owner = THIS_MODULE,
|
|
|
-+ .n_voltages = 0x20,
|
|
|
-+ .uV_step = 25000,
|
|
|
-+ .linear_min_sel = 0,
|
|
|
-+ .min_uV = 2800000,
|
|
|
-+ .vsel_reg = HW_POWER_VDDIOCTRL,
|
|
|
-+ .vsel_mask = 0x1f,
|
|
|
-+ .ops = &mxs_ldo_ops,
|
|
|
-+ },
|
|
|
-+ .ctrl_reg = HW_POWER_VDDIOCTRL,
|
|
|
-+ .disable_fet_mask = 1 << 16,
|
|
|
-+ .linreg_offset_mask = 3 << 12,
|
|
|
-+ .linreg_offset_shift = 12,
|
|
|
-+ .get_power_source = get_vddio_power_source,
|
|
|
-+};
|
|
|
-+
|
|
|
-+static const struct mxs_reg_info imx28_info_vddio = {
|
|
|
-+ .desc = {
|
|
|
-+ .name = "vddio",
|
|
|
-+ .id = MXS_VDDIO,
|
|
|
-+ .type = REGULATOR_VOLTAGE,
|
|
|
-+ .owner = THIS_MODULE,
|
|
|
-+ .n_voltages = 0x11,
|
|
|
-+ .uV_step = 50000,
|
|
|
-+ .linear_min_sel = 0,
|
|
|
-+ .min_uV = 2800000,
|
|
|
-+ .vsel_reg = HW_POWER_VDDIOCTRL,
|
|
|
-+ .vsel_mask = 0x1f,
|
|
|
-+ .ops = &mxs_ldo_ops,
|
|
|
-+ },
|
|
|
-+ .ctrl_reg = HW_POWER_VDDIOCTRL,
|
|
|
-+ .disable_fet_mask = 1 << 16,
|
|
|
-+ .linreg_offset_mask = 3 << 12,
|
|
|
-+ .linreg_offset_shift = 12,
|
|
|
-+ .get_power_source = get_vddio_power_source,
|
|
|
-+};
|
|
|
-+
|
|
|
-+static const struct mxs_reg_info mxs_info_vdda = {
|
|
|
-+ .desc = {
|
|
|
-+ .name = "vdda",
|
|
|
-+ .id = MXS_VDDA,
|
|
|
-+ .type = REGULATOR_VOLTAGE,
|
|
|
-+ .owner = THIS_MODULE,
|
|
|
-+ .n_voltages = 0x20,
|
|
|
-+ .uV_step = 25000,
|
|
|
-+ .linear_min_sel = 0,
|
|
|
-+ .min_uV = 1500000,
|
|
|
-+ .vsel_reg = HW_POWER_VDDACTRL,
|
|
|
-+ .vsel_mask = 0x1f,
|
|
|
-+ .ops = &mxs_ldo_ops,
|
|
|
-+ .enable_mask = (1 << 17),
|
|
|
-+ },
|
|
|
-+ .ctrl_reg = HW_POWER_VDDACTRL,
|
|
|
-+ .disable_fet_mask = 1 << 16,
|
|
|
-+ .linreg_offset_mask = 3 << 12,
|
|
|
-+ .linreg_offset_shift = 12,
|
|
|
-+ .get_power_source = get_vdda_vddd_power_source,
|
|
|
-+};
|
|
|
-+
|
|
|
-+static const struct mxs_reg_info mxs_info_vddd = {
|
|
|
-+ .desc = {
|
|
|
-+ .name = "vddd",
|
|
|
-+ .id = MXS_VDDD,
|
|
|
-+ .type = REGULATOR_VOLTAGE,
|
|
|
-+ .owner = THIS_MODULE,
|
|
|
-+ .n_voltages = 0x20,
|
|
|
-+ .uV_step = 25000,
|
|
|
-+ .linear_min_sel = 0,
|
|
|
-+ .min_uV = 800000,
|
|
|
-+ .vsel_reg = HW_POWER_VDDDCTRL,
|
|
|
-+ .vsel_mask = 0x1f,
|
|
|
-+ .ops = &mxs_ldo_ops,
|
|
|
-+ .enable_mask = (1 << 21),
|
|
|
-+ },
|
|
|
-+ .ctrl_reg = HW_POWER_VDDDCTRL,
|
|
|
-+ .disable_fet_mask = 1 << 20,
|
|
|
-+ .linreg_offset_mask = 3 << 16,
|
|
|
-+ .linreg_offset_shift = 16,
|
|
|
-+ .get_power_source = get_vdda_vddd_power_source,
|
|
|
-+};
|
|
|
-+
|
|
|
-+static const struct of_device_id of_mxs_regulator_match[] = {
|
|
|
-+ { .compatible = "fsl,imx23-dcdc", .data = &mxs_info_dcdc },
|
|
|
-+ { .compatible = "fsl,imx28-dcdc", .data = &mxs_info_dcdc },
|
|
|
-+ { .compatible = "fsl,imx23-vddio", .data = &imx23_info_vddio },
|
|
|
-+ { .compatible = "fsl,imx23-vdda", .data = &mxs_info_vdda },
|
|
|
-+ { .compatible = "fsl,imx23-vddd", .data = &mxs_info_vddd },
|
|
|
-+ { .compatible = "fsl,imx28-vddio", .data = &imx28_info_vddio },
|
|
|
-+ { .compatible = "fsl,imx28-vdda", .data = &mxs_info_vdda },
|
|
|
-+ { .compatible = "fsl,imx28-vddd", .data = &mxs_info_vddd },
|
|
|
-+ { /* end */ }
|
|
|
-+};
|
|
|
-+MODULE_DEVICE_TABLE(of, of_mxs_regulator_match);
|
|
|
-+
|
|
|
-+static int mxs_regulator_probe(struct platform_device *pdev)
|
|
|
-+{
|
|
|
-+ struct device *dev = &pdev->dev;
|
|
|
-+ const struct of_device_id *match;
|
|
|
-+ struct device_node *parent_np;
|
|
|
-+ struct regulator_dev *rdev = NULL;
|
|
|
-+ struct mxs_reg_info *info;
|
|
|
-+ struct regulator_init_data *initdata;
|
|
|
-+ struct regulator_config config = { };
|
|
|
-+ u32 switch_freq;
|
|
|
-+
|
|
|
-+ match = of_match_device(of_mxs_regulator_match, dev);
|
|
|
-+ if (!match) {
|
|
|
-+ /* We do not expect this to happen */
|
|
|
-+ dev_err(dev, "%s: Unable to match device\n", __func__);
|
|
|
-+ return -ENODEV;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ info = devm_kmemdup(dev, match->data, sizeof(struct mxs_reg_info),
|
|
|
-+ GFP_KERNEL);
|
|
|
-+ if (!info)
|
|
|
-+ return -ENOMEM;
|
|
|
-+
|
|
|
-+ initdata = of_get_regulator_init_data(dev, dev->of_node, &info->desc);
|
|
|
-+ if (!initdata) {
|
|
|
-+ dev_err(dev, "missing regulator init data\n");
|
|
|
-+ return -EINVAL;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ parent_np = of_get_parent(dev->of_node);
|
|
|
-+ if (!parent_np)
|
|
|
-+ return -ENODEV;
|
|
|
-+ config.regmap = syscon_node_to_regmap(parent_np);
|
|
|
-+ of_node_put(parent_np);
|
|
|
-+ if (IS_ERR(config.regmap))
|
|
|
-+ return PTR_ERR(config.regmap);
|
|
|
-+
|
|
|
-+ config.dev = dev;
|
|
|
-+ config.init_data = initdata;
|
|
|
-+ config.driver_data = info;
|
|
|
-+ config.of_node = dev->of_node;
|
|
|
-+
|
|
|
-+ rdev = devm_regulator_register(dev, &info->desc, &config);
|
|
|
-+ if (IS_ERR(rdev)) {
|
|
|
-+ int ret = PTR_ERR(rdev);
|
|
|
-+
|
|
|
-+ dev_err(dev, "%s: failed to register regulator(%d)\n",
|
|
|
-+ __func__, ret);
|
|
|
-+ return ret;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!of_property_read_u32(dev->of_node, "switching-frequency",
|
|
|
-+ &switch_freq))
|
|
|
-+ mxs_set_dcdc_freq(rdev, switch_freq);
|
|
|
-+
|
|
|
-+ platform_set_drvdata(pdev, rdev);
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static struct platform_driver mxs_regulator_driver = {
|
|
|
-+ .driver = {
|
|
|
-+ .name = "mxs_regulator",
|
|
|
-+ .of_match_table = of_mxs_regulator_match,
|
|
|
-+ },
|
|
|
-+ .probe = mxs_regulator_probe,
|
|
|
-+};
|
|
|
-+
|
|
|
-+module_platform_driver(mxs_regulator_driver);
|
|
|
-+
|
|
|
-+MODULE_AUTHOR("Stefan Wahren <[email protected]>");
|
|
|
-+MODULE_DESCRIPTION("Freescale MXS regulators");
|
|
|
-+MODULE_LICENSE("GPL v2");
|
|
|
-+MODULE_ALIAS("platform:mxs_regulator");
|