|
@@ -459,3 +459,158 @@ static int n8x0_mmc_late_init(struct device *dev)
|
|
|
|
|
|
/* All slot pin bits seem to be inversed until first switch change */
|
|
/* All slot pin bits seem to be inversed until first switch change */
|
|
if (r == 0xf || r == (0xf & ~bit))
|
|
if (r == 0xf || r == (0xf & ~bit))
|
|
|
|
+ r = ~r;
|
|
|
|
+
|
|
|
|
+ if (r & bit)
|
|
|
|
+ *openp = 1;
|
|
|
|
+ else
|
|
|
|
+ *openp = 0;
|
|
|
|
+
|
|
|
|
+ r = menelaus_register_mmc_callback(n8x0_mmc_callback, NULL);
|
|
|
|
+
|
|
|
|
+ return r;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void n8x0_mmc_shutdown(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ int vs2sel;
|
|
|
|
+
|
|
|
|
+ if (machine_is_nokia_n800())
|
|
|
|
+ vs2sel = 0;
|
|
|
|
+ else
|
|
|
|
+ vs2sel = 2;
|
|
|
|
+
|
|
|
|
+ menelaus_set_mmc_slot(1, 0, 0, 0);
|
|
|
|
+ menelaus_set_mmc_slot(2, 0, vs2sel, 0);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void n8x0_mmc_cleanup(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ menelaus_unregister_mmc_callback();
|
|
|
|
+
|
|
|
|
+ gpio_free(N8X0_SLOT_SWITCH_GPIO);
|
|
|
|
+
|
|
|
|
+ if (machine_is_nokia_n810()) {
|
|
|
|
+ gpio_free(N810_EMMC_VSD_GPIO);
|
|
|
|
+ gpio_free(N810_EMMC_VIO_GPIO);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * MMC controller1 has two slots that are multiplexed via I2C.
|
|
|
|
+ * MMC controller2 is not in use.
|
|
|
|
+ */
|
|
|
|
+static struct omap_mmc_platform_data mmc1_data = {
|
|
|
|
+ .nr_slots = 2,
|
|
|
|
+ .switch_slot = n8x0_mmc_switch_slot,
|
|
|
|
+ .init = n8x0_mmc_late_init,
|
|
|
|
+ .cleanup = n8x0_mmc_cleanup,
|
|
|
|
+ .shutdown = n8x0_mmc_shutdown,
|
|
|
|
+ .max_freq = 24000000,
|
|
|
|
+ .slots[0] = {
|
|
|
|
+ .wires = 4,
|
|
|
|
+ .set_power = n8x0_mmc_set_power,
|
|
|
|
+ .set_bus_mode = n8x0_mmc_set_bus_mode,
|
|
|
|
+ .get_cover_state = n8x0_mmc_get_cover_state,
|
|
|
|
+ .ocr_mask = MMC_VDD_165_195 | MMC_VDD_30_31 |
|
|
|
|
+ MMC_VDD_32_33 | MMC_VDD_33_34,
|
|
|
|
+ .name = "internal",
|
|
|
|
+ },
|
|
|
|
+ .slots[1] = {
|
|
|
|
+ .set_power = n8x0_mmc_set_power,
|
|
|
|
+ .set_bus_mode = n8x0_mmc_set_bus_mode,
|
|
|
|
+ .get_cover_state = n8x0_mmc_get_cover_state,
|
|
|
|
+ .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21 |
|
|
|
|
+ MMC_VDD_21_22 | MMC_VDD_22_23 |
|
|
|
|
+ MMC_VDD_23_24 | MMC_VDD_24_25 |
|
|
|
|
+ MMC_VDD_27_28 | MMC_VDD_28_29 |
|
|
|
|
+ MMC_VDD_29_30 | MMC_VDD_30_31 |
|
|
|
|
+ MMC_VDD_32_33 | MMC_VDD_33_34,
|
|
|
|
+ .name = "external",
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
|
|
|
|
+
|
|
|
|
+static struct gpio n810_emmc_gpios[] __initdata = {
|
|
|
|
+ { N810_EMMC_VSD_GPIO, GPIOF_OUT_INIT_LOW, "MMC slot 2 Vddf" },
|
|
|
|
+ { N810_EMMC_VIO_GPIO, GPIOF_OUT_INIT_LOW, "MMC slot 2 Vdd" },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void __init n8x0_mmc_init(void)
|
|
|
|
+{
|
|
|
|
+ int err;
|
|
|
|
+
|
|
|
|
+ if (machine_is_nokia_n810()) {
|
|
|
|
+ mmc1_data.slots[0].name = "external";
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Some Samsung Movinand chips do not like open-ended
|
|
|
|
+ * multi-block reads and fall to braind-dead state
|
|
|
|
+ * while doing so. Reducing the number of blocks in
|
|
|
|
+ * the transfer or delays in clock disable do not help
|
|
|
|
+ */
|
|
|
|
+ mmc1_data.slots[1].name = "internal";
|
|
|
|
+ mmc1_data.slots[1].ban_openended = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ err = gpio_request_one(N8X0_SLOT_SWITCH_GPIO, GPIOF_OUT_INIT_LOW,
|
|
|
|
+ "MMC slot switch");
|
|
|
|
+ if (err)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ if (machine_is_nokia_n810()) {
|
|
|
|
+ err = gpio_request_array(n810_emmc_gpios,
|
|
|
|
+ ARRAY_SIZE(n810_emmc_gpios));
|
|
|
|
+ if (err) {
|
|
|
|
+ gpio_free(N8X0_SLOT_SWITCH_GPIO);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mmc_data[0] = &mmc1_data;
|
|
|
|
+ omap242x_init_mmc(mmc_data);
|
|
|
|
+}
|
|
|
|
+#else
|
|
|
|
+
|
|
|
|
+void __init n8x0_mmc_init(void)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+#endif /* CONFIG_MMC_OMAP */
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_MENELAUS
|
|
|
|
+
|
|
|
|
+static int n8x0_auto_sleep_regulators(void)
|
|
|
|
+{
|
|
|
|
+ u32 val;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ val = EN_VPLL_SLEEP | EN_VMMC_SLEEP \
|
|
|
|
+ | EN_VAUX_SLEEP | EN_VIO_SLEEP \
|
|
|
|
+ | EN_VMEM_SLEEP | EN_DC3_SLEEP \
|
|
|
|
+ | EN_VC_SLEEP | EN_DC2_SLEEP;
|
|
|
|
+
|
|
|
|
+ ret = menelaus_set_regulator_sleep(1, val);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ pr_err("Could not set regulators to sleep on menelaus: %u\n",
|
|
|
|
+ ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int n8x0_auto_voltage_scale(void)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ ret = menelaus_set_vcore_hw(1400, 1050);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ pr_err("Could not set VCORE voltage on menelaus: %u\n", ret);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int n8x0_menelaus_late_init(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ int ret;
|