summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mx5/mx50_rdp_pmic_mc34708.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-mx5/mx50_rdp_pmic_mc34708.c')
-rw-r--r--arch/arm/mach-mx5/mx50_rdp_pmic_mc34708.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/arch/arm/mach-mx5/mx50_rdp_pmic_mc34708.c b/arch/arm/mach-mx5/mx50_rdp_pmic_mc34708.c
new file mode 100644
index 000000000000..4fcc9d6785fa
--- /dev/null
+++ b/arch/arm/mach-mx5/mx50_rdp_pmic_mc34708.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+#include <linux/pmic_external.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/mc34708/core.h>
+#include <mach/irqs.h>
+#include <mach/iomux-mx50.h>
+
+#include <mach/gpio.h>
+/*
+ * Convenience conversion.
+ * Here atm, maybe there is somewhere better for this.
+ */
+#define mV_to_uV(mV) (mV * 1000)
+#define uV_to_mV(uV) (uV / 1000)
+#define V_to_uV(V) (mV_to_uV(V * 1000))
+#define uV_to_V(uV) (uV_to_mV(uV) / 1000)
+
+/* regulator standby mask */
+#define GEN1_STBY_MASK (1 << 1)
+#define GEN2_STBY_MASK (1 << 13)
+#define PLL_STBY_MASK (1 << 16)
+#define USB2_STBY_MASK (1 << 19)
+#define USB_EN_MASK (1 << 3)
+
+
+#define REG_MODE_0_ALL_MASK (GEN1_STBY_MASK | PLL_STBY_MASK\
+ | GEN2_STBY_MASK | USB2_STBY_MASK)
+
+#define SW1A_MODE_MASK (0xf << 0)
+#define SW2_MODE_MASK (0xf << 14)
+#define SW1A_MODE_VALUE (0xd << 0)
+#define SW2_MODE_VALUE (0xd << 14)
+
+#define REG_SW_1_2_MASK (SW1A_MODE_MASK | SW2_MODE_MASK)
+#define REG_SW_1_2_VALUE (SW1A_MODE_VALUE | SW2_MODE_VALUE)
+
+#define SW3_MODE_MASK (0xf << 0)
+#define SW4A_MODE_MASK (0xf << 6)
+#define SW4B_MODE_MASK (0xf << 12)
+#define SW5_MODE_MASK (0xf << 18)
+
+#define SW3_MODE_VALUE (0xd << 0)
+#define SW4A_MODE_VALUE (0xd << 6)
+#define SW4B_MODE_VALUE (0xd << 12)
+#define SW5_MODE_VALUE (0xd << 18)
+
+#define REG_SW_3_4_5_MASK (SW3_MODE_MASK | SW4A_MODE_MASK\
+ | SW4B_MODE_MASK | SW5_MODE_MASK)
+#define REG_SW_3_4_5_VALUE (SW3_MODE_VALUE | SW4A_MODE_VALUE\
+ | SW4B_MODE_VALUE | SW5_MODE_VALUE)
+
+#define SWBST_MODE_MASK (0x3 << 5)
+#define SWBST_MODE_VALUE (0x1 << 5)
+
+#define REG_SWBST_MODE_MASK (SWBST_MODE_MASK)
+#define REG_SWBST_MODE_VALUE (SWBST_MODE_VALUE)
+
+#define SWHOLD_MASK (0x1 << 12)
+
+#define ECSPI2_MISO_GP4_18 (3 * 32 + 18)
+
+struct mc34708;
+
+static struct regulator_init_data sw1a_init = {
+ .constraints = {
+ .name = "SW1",
+ .min_uV = 650000,
+ .max_uV = 1437500,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .valid_modes_mask = 0,
+ .always_on = 1,
+ .boot_on = 1,
+ .initial_state = PM_SUSPEND_MEM,
+ .state_mem = {
+ .uV = 850000,
+ .mode = REGULATOR_MODE_NORMAL,
+ .enabled = 1,
+ },
+ },
+};
+
+static struct regulator_init_data sw1b_init = {
+ .constraints = {
+ .name = "SW1B",
+ .min_uV = 650000,
+ .max_uV = 1437500,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .valid_modes_mask = 0,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+};
+
+static struct regulator_init_data sw2_init = {
+ .constraints = {
+ .name = "SW2",
+ .min_uV = 650000,
+ .max_uV = 1437500,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ .initial_state = PM_SUSPEND_MEM,
+ .state_mem = {
+ .uV = 950000,
+ .mode = REGULATOR_MODE_NORMAL,
+ .enabled = 1,
+ },
+ }
+};
+
+static struct regulator_init_data sw3_init = {
+ .constraints = {
+ .name = "SW3",
+ .min_uV = 650000,
+ .max_uV = 1425000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ .initial_state = PM_SUSPEND_MEM,
+ .state_mem = {
+ .uV = 950000,
+ .mode = REGULATOR_MODE_NORMAL,
+ .enabled = 1,
+ },
+ }
+};
+
+static struct regulator_init_data sw4a_init = {
+ .constraints = {
+ .name = "SW4A",
+ .min_uV = mV_to_uV(1200),
+ .max_uV = mV_to_uV(3300),
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data sw4b_init = {
+ .constraints = {
+ .name = "SW4B",
+ .min_uV = mV_to_uV(1200),
+ .max_uV = mV_to_uV(3300),
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data sw5_init = {
+ .constraints = {
+ .name = "SW5",
+ .min_uV = mV_to_uV(1200),
+ .max_uV = mV_to_uV(1975),
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vrefddr_init = {
+ .constraints = {
+ .name = "VREFDDR",
+ .always_on = 1,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vusb_init = {
+ .constraints = {
+ .name = "VUSB",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data swbst_init = {
+ .constraints = {
+ .name = "SWBST",
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data vpll_init = {
+ .constraints = {
+ .name = "VPLL",
+ .min_uV = mV_to_uV(1200),
+ .max_uV = mV_to_uV(1800),
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .boot_on = 1,
+ },
+};
+
+static struct regulator_init_data vdac_init = {
+ .constraints = {
+ .name = "VDAC",
+ .min_uV = mV_to_uV(2500),
+ .max_uV = mV_to_uV(2775),
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data vusb2_init = {
+ .constraints = {
+ .name = "VUSB2",
+ .min_uV = mV_to_uV(2500),
+ .max_uV = mV_to_uV(3000),
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .boot_on = 1,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data vgen1_init = {
+ .constraints = {
+ .name = "VGEN1",
+ .min_uV = mV_to_uV(1200),
+ .max_uV = mV_to_uV(1550),
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ }
+};
+
+static struct regulator_init_data vgen2_init = {
+ .constraints = {
+ .name = "VGEN2",
+ .min_uV = mV_to_uV(2500),
+ .max_uV = mV_to_uV(3300),
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .always_on = 1,
+ }
+};
+
+
+static int mc34708_regulator_init(struct mc34708 *mc34708)
+{
+ unsigned int value, register_mask;
+
+ pmic_read_reg(REG_MC34708_IDENTIFICATION, &value, 0xffffff);
+ pr_info("PMIC MC34708 ID:0x%x\n", value);
+
+ /* enable standby controll for mode0 regulators */
+ pmic_read_reg(REG_MC34708_MODE_0, &value, 0xffffff);
+ value |= REG_MODE_0_ALL_MASK;
+ value &= ~USB_EN_MASK;
+ pmic_write_reg(REG_MC34708_MODE_0, value, 0xffffff);
+
+ /* enable standby controll for mode0 regulators */
+ pmic_read_reg(REG_MC34708_SW_1_2_OP, &value, 0xffffff);
+ value &= ~REG_SW_1_2_MASK;
+ value |= REG_SW_1_2_VALUE;
+ pmic_write_reg(REG_MC34708_SW_1_2_OP, value, 0xffffff);
+
+ /* enable standby controll for mode0 regulators */
+ pmic_read_reg(REG_MC34708_SW_3_4_5_OP, &value, 0xffffff);
+ value &= ~REG_SW_3_4_5_MASK;
+ value |= REG_SW_3_4_5_VALUE;
+ pmic_write_reg(REG_MC34708_SW_3_4_5_OP, value, 0xffffff);
+
+ /* enable standby controll for mode0 regulators */
+ pmic_read_reg(REG_MC34708_SWBST, &value, 0xffffff);
+ value &= ~REG_SWBST_MODE_MASK;
+ value |= REG_SWBST_MODE_VALUE;
+ pmic_write_reg(REG_MC34708_SWBST, value, 0xffffff);
+
+ /* clear SWHOLD bit to enable USB MUX */
+ pmic_read_reg(REG_MC34708_USB_CONTROL, &value, 0xffffff);
+ value &= ~SWHOLD_MASK;
+ pmic_write_reg(REG_MC34708_USB_CONTROL, value, 0xffffff);
+
+ pr_info("Initializing mc34708 regulators for mx50 rdp.\n");
+
+ mc34708_register_regulator(mc34708, MC34708_SW1A, &sw1a_init);
+ mc34708_register_regulator(mc34708, MC34708_SW1B, &sw1b_init);
+ mc34708_register_regulator(mc34708, MC34708_SW2, &sw2_init);
+ mc34708_register_regulator(mc34708, MC34708_SW3, &sw3_init);
+ mc34708_register_regulator(mc34708, MC34708_SW4A, &sw4a_init);
+ mc34708_register_regulator(mc34708, MC34708_SW4B, &sw4b_init);
+ mc34708_register_regulator(mc34708, MC34708_SW5, &sw5_init);
+ mc34708_register_regulator(mc34708, MC34708_SWBST, &swbst_init);
+ mc34708_register_regulator(mc34708, MC34708_VPLL, &vpll_init);
+ mc34708_register_regulator(mc34708, MC34708_VREFDDR, &vrefddr_init);
+ mc34708_register_regulator(mc34708, MC34708_VDAC, &vdac_init);
+ mc34708_register_regulator(mc34708, MC34708_VUSB, &vusb_init);
+ mc34708_register_regulator(mc34708, MC34708_VUSB2, &vusb2_init);
+ mc34708_register_regulator(mc34708, MC34708_VGEN1, &vgen1_init);
+ mc34708_register_regulator(mc34708, MC34708_VGEN2, &vgen2_init);
+
+ regulator_has_full_constraints();
+
+ return 0;
+}
+
+static struct mc34708_platform_data mc34708_plat = {
+ .init = mc34708_regulator_init,
+};
+
+static struct spi_board_info __initdata mc34708_spi_device = {
+ .modalias = "mc34708",
+ .irq = gpio_to_irq(ECSPI2_MISO_GP4_18),
+ .max_speed_hz = 6000000, /* max spi SCK clock speed in HZ */
+ .bus_num = 3,
+ .chip_select = 0,
+ .platform_data = &mc34708_plat,
+};
+
+
+int __init mx50_rdp_init_mc34708(void)
+{
+ return spi_register_board_info(&mc34708_spi_device, 1);
+}