^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Motorola Mapphone MDM6600 modem GPIO controlled USB PHY driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2018 Tony Lindgren <tony@atomide.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/gpio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/phy/phy.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/pinctrl/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define PHY_MDM6600_PHY_DELAY_MS 4000 /* PHY enable 2.2s to 3.5s */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define PHY_MDM6600_ENABLED_DELAY_MS 8000 /* 8s more total for MDM6600 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define PHY_MDM6600_WAKE_KICK_MS 600 /* time on after GPIO toggle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define MDM6600_MODEM_IDLE_DELAY_MS 1000 /* modem after USB suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define MDM6600_MODEM_WAKE_DELAY_MS 200 /* modem response after idle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) enum phy_mdm6600_ctrl_lines {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) PHY_MDM6600_ENABLE, /* USB PHY enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) PHY_MDM6600_POWER, /* Device power */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) PHY_MDM6600_RESET, /* Device reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) PHY_MDM6600_NR_CTRL_LINES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) enum phy_mdm6600_bootmode_lines {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) PHY_MDM6600_MODE0, /* out USB mode0 and OOB wake */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) PHY_MDM6600_MODE1, /* out USB mode1, in OOB wake */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) PHY_MDM6600_NR_MODE_LINES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) enum phy_mdm6600_cmd_lines {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) PHY_MDM6600_CMD0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) PHY_MDM6600_CMD1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) PHY_MDM6600_CMD2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) PHY_MDM6600_NR_CMD_LINES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) enum phy_mdm6600_status_lines {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) PHY_MDM6600_STATUS0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) PHY_MDM6600_STATUS1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) PHY_MDM6600_STATUS2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) PHY_MDM6600_NR_STATUS_LINES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * MDM6600 command codes. These are based on Motorola Mapphone Linux
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * kernel tree.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) enum phy_mdm6600_cmd {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) PHY_MDM6600_CMD_BP_PANIC_ACK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) PHY_MDM6600_CMD_DATA_ONLY_BYPASS, /* Reroute USB to CPCAP PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) PHY_MDM6600_CMD_FULL_BYPASS, /* Reroute USB to CPCAP PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) PHY_MDM6600_CMD_NO_BYPASS, /* Request normal USB mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) PHY_MDM6600_CMD_BP_SHUTDOWN_REQ, /* Request device power off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) PHY_MDM6600_CMD_BP_UNKNOWN_5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) PHY_MDM6600_CMD_BP_UNKNOWN_6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) PHY_MDM6600_CMD_UNDEFINED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * MDM6600 status codes. These are based on Motorola Mapphone Linux
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * kernel tree.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) enum phy_mdm6600_status {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) PHY_MDM6600_STATUS_PANIC, /* Seems to be really off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) PHY_MDM6600_STATUS_PANIC_BUSY_WAIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) PHY_MDM6600_STATUS_QC_DLOAD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) PHY_MDM6600_STATUS_RAM_DOWNLOADER, /* MDM6600 USB flashing mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) PHY_MDM6600_STATUS_PHONE_CODE_AWAKE, /* MDM6600 normal USB mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) PHY_MDM6600_STATUS_PHONE_CODE_ASLEEP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) PHY_MDM6600_STATUS_SHUTDOWN_ACK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) PHY_MDM6600_STATUS_UNDEFINED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static const char * const
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) phy_mdm6600_status_name[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) "off", "busy", "qc_dl", "ram_dl", "awake",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) "asleep", "shutdown", "undefined",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct phy_mdm6600 {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) struct phy *generic_phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct phy_provider *phy_provider;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct gpio_desc *ctrl_gpios[PHY_MDM6600_NR_CTRL_LINES];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct gpio_descs *mode_gpios;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct gpio_descs *status_gpios;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct gpio_descs *cmd_gpios;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct delayed_work bootup_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct delayed_work status_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct delayed_work modem_wake_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct completion ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) bool enabled; /* mdm6600 phy enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) bool running; /* mdm6600 boot done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) bool awake; /* mdm6600 respnds on n_gsm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int phy_mdm6600_init(struct phy *x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct phy_mdm6600 *ddata = phy_get_drvdata(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (!ddata->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) gpiod_set_value_cansleep(enable_gpio, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static int phy_mdm6600_power_on(struct phy *x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct phy_mdm6600 *ddata = phy_get_drvdata(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (!ddata->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) error = pinctrl_pm_select_default_state(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) dev_warn(ddata->dev, "%s: error with default_state: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) gpiod_set_value_cansleep(enable_gpio, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* Allow aggressive PM for USB, it's only needed for n_gsm port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (pm_runtime_enabled(&x->dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) phy_pm_runtime_put(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int phy_mdm6600_power_off(struct phy *x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct phy_mdm6600 *ddata = phy_get_drvdata(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (!ddata->enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* Paired with phy_pm_runtime_put() in phy_mdm6600_power_on() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (pm_runtime_enabled(&x->dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) error = phy_pm_runtime_get(x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (error < 0 && error != -EINPROGRESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) dev_warn(ddata->dev, "%s: phy_pm_runtime_get: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) gpiod_set_value_cansleep(enable_gpio, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) error = pinctrl_pm_select_sleep_state(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) dev_warn(ddata->dev, "%s: error with sleep_state: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static const struct phy_ops gpio_usb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .init = phy_mdm6600_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .power_on = phy_mdm6600_power_on,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .power_off = phy_mdm6600_power_off,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * phy_mdm6600_cmd() - send a command request to mdm6600
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * @ddata: device driver data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * @val: value of cmd to be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * Configures the three command request GPIOs to the specified value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) DECLARE_BITMAP(values, PHY_MDM6600_NR_CMD_LINES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) values[0] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ddata->cmd_gpios->desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) ddata->cmd_gpios->info, values);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * phy_mdm6600_status() - read mdm6600 status lines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * @work: work structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) static void phy_mdm6600_status(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) struct phy_mdm6600 *ddata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) DECLARE_BITMAP(values, PHY_MDM6600_NR_STATUS_LINES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) ddata = container_of(work, struct phy_mdm6600, status_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) dev = ddata->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) ddata->status_gpios->desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) ddata->status_gpios->info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) values);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) ddata->status = values[0] & ((1 << PHY_MDM6600_NR_STATUS_LINES) - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) dev_info(dev, "modem status: %i %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) ddata->status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) phy_mdm6600_status_name[ddata->status]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) complete(&ddata->ack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static irqreturn_t phy_mdm6600_irq_thread(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) struct phy_mdm6600 *ddata = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) schedule_delayed_work(&ddata->status_work, msecs_to_jiffies(10));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) * phy_mdm6600_wakeirq_thread - handle mode1 line OOB wake after booting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) * @irq: interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) * @data: interrupt handler data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * GPIO mode1 is used initially as output to configure the USB boot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) * mode for mdm6600. After booting it is used as input for OOB wake
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * signal from mdm6600 to the SoC. Just use it for debug info only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * for now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) static irqreturn_t phy_mdm6600_wakeirq_thread(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) struct phy_mdm6600 *ddata = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) struct gpio_desc *mode_gpio1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) int error, wakeup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) mode_gpio1 = ddata->mode_gpios->desc[PHY_MDM6600_MODE1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) wakeup = gpiod_get_value(mode_gpio1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (!wakeup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) dev_dbg(ddata->dev, "OOB wake on mode_gpio1: %i\n", wakeup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) error = pm_runtime_get_sync(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) pm_runtime_put_noidle(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) /* Just wake-up and kick the autosuspend timer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) pm_runtime_mark_last_busy(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) pm_runtime_put_autosuspend(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * phy_mdm6600_init_irq() - initialize mdm6600 status IRQ lines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * @ddata: device driver data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) static void phy_mdm6600_init_irq(struct phy_mdm6600 *ddata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) struct device *dev = ddata->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) int i, error, irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) for (i = PHY_MDM6600_STATUS0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) i <= PHY_MDM6600_STATUS2; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) struct gpio_desc *gpio = ddata->status_gpios->desc[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) irq = gpiod_to_irq(gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (irq <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) error = devm_request_threaded_irq(dev, irq, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) phy_mdm6600_irq_thread,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) IRQF_TRIGGER_RISING |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) IRQF_TRIGGER_FALLING |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) "mdm6600",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) dev_warn(dev, "no modem status irq%i: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) irq, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) struct phy_mdm6600_map {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) int direction;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static const struct phy_mdm6600_map
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) phy_mdm6600_ctrl_gpio_map[PHY_MDM6600_NR_CTRL_LINES] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) { "enable", GPIOD_OUT_LOW, }, /* low = phy disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) { "power", GPIOD_OUT_LOW, }, /* low = off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) { "reset", GPIOD_OUT_HIGH, }, /* high = reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) * phy_mdm6600_init_lines() - initialize mdm6600 GPIO lines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) * @ddata: device driver data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) static int phy_mdm6600_init_lines(struct phy_mdm6600 *ddata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) struct device *dev = ddata->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* MDM6600 control lines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) for (i = 0; i < ARRAY_SIZE(phy_mdm6600_ctrl_gpio_map); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) const struct phy_mdm6600_map *map =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) &phy_mdm6600_ctrl_gpio_map[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) struct gpio_desc **gpio = &ddata->ctrl_gpios[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) *gpio = devm_gpiod_get(dev, map->name, map->direction);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (IS_ERR(*gpio)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) dev_info(dev, "gpio %s error %li\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) map->name, PTR_ERR(*gpio));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return PTR_ERR(*gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* MDM6600 USB start-up mode output lines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) ddata->mode_gpios = devm_gpiod_get_array(dev, "motorola,mode",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) GPIOD_OUT_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (IS_ERR(ddata->mode_gpios))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) return PTR_ERR(ddata->mode_gpios);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (ddata->mode_gpios->ndescs != PHY_MDM6600_NR_MODE_LINES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) /* MDM6600 status input lines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) ddata->status_gpios = devm_gpiod_get_array(dev, "motorola,status",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) GPIOD_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (IS_ERR(ddata->status_gpios))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) return PTR_ERR(ddata->status_gpios);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (ddata->status_gpios->ndescs != PHY_MDM6600_NR_STATUS_LINES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) /* MDM6600 cmd output lines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) ddata->cmd_gpios = devm_gpiod_get_array(dev, "motorola,cmd",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) GPIOD_OUT_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (IS_ERR(ddata->cmd_gpios))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return PTR_ERR(ddata->cmd_gpios);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (ddata->cmd_gpios->ndescs != PHY_MDM6600_NR_CMD_LINES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) * phy_mdm6600_device_power_on() - power on mdm6600 device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) * @ddata: device driver data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) * To get the integrated USB phy in MDM6600 takes some hoops. We must ensure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * the shared USB bootmode GPIOs are configured, then request modem start-up,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) * reset and power-up.. And then we need to recycle the shared USB bootmode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) * GPIOs as they are also used for Out of Band (OOB) wake for the USB and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) * TS 27.010 serial mux.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) static int phy_mdm6600_device_power_on(struct phy_mdm6600 *ddata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) struct gpio_desc *mode_gpio0, *mode_gpio1, *reset_gpio, *power_gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) int error = 0, wakeirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) mode_gpio0 = ddata->mode_gpios->desc[PHY_MDM6600_MODE0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) mode_gpio1 = ddata->mode_gpios->desc[PHY_MDM6600_MODE1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) power_gpio = ddata->ctrl_gpios[PHY_MDM6600_POWER];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) * Shared GPIOs must be low for normal USB mode. After booting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * they are used for OOB wake signaling. These can be also used
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * to configure USB flashing mode later on based on a module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * parameter.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) gpiod_set_value_cansleep(mode_gpio0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) gpiod_set_value_cansleep(mode_gpio1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) /* Request start-up mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) phy_mdm6600_cmd(ddata, PHY_MDM6600_CMD_NO_BYPASS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) /* Request a reset first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) gpiod_set_value_cansleep(reset_gpio, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) msleep(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) /* Toggle power GPIO to request mdm6600 to start */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) gpiod_set_value_cansleep(power_gpio, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) msleep(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) gpiod_set_value_cansleep(power_gpio, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * Looks like the USB PHY needs between 2.2 to 4 seconds.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) * If we try to use it before that, we will get L3 errors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) * from omap-usb-host trying to access the PHY. See also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) * phy_mdm6600_init() for -EPROBE_DEFER.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) msleep(PHY_MDM6600_PHY_DELAY_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) ddata->enabled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) /* Booting up the rest of MDM6600 will take total about 8 seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) dev_info(ddata->dev, "Waiting for power up request to complete..\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (wait_for_completion_timeout(&ddata->ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) msecs_to_jiffies(PHY_MDM6600_ENABLED_DELAY_MS))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (ddata->status > PHY_MDM6600_STATUS_PANIC &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) ddata->status < PHY_MDM6600_STATUS_SHUTDOWN_ACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) dev_info(ddata->dev, "Powered up OK\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) ddata->enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) error = -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) dev_err(ddata->dev, "Timed out powering up\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) /* Reconfigure mode1 GPIO as input for OOB wake */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) gpiod_direction_input(mode_gpio1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) wakeirq = gpiod_to_irq(mode_gpio1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (wakeirq <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) return wakeirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) error = devm_request_threaded_irq(ddata->dev, wakeirq, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) phy_mdm6600_wakeirq_thread,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) IRQF_TRIGGER_RISING |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) IRQF_TRIGGER_FALLING |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) "mdm6600-wake",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) dev_warn(ddata->dev, "no modem wakeirq irq%i: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) wakeirq, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) ddata->running = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * phy_mdm6600_device_power_off() - power off mdm6600 device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) * @ddata: device driver data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) static void phy_mdm6600_device_power_off(struct phy_mdm6600 *ddata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) struct gpio_desc *reset_gpio =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) ddata->ctrl_gpios[PHY_MDM6600_RESET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) ddata->enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) phy_mdm6600_cmd(ddata, PHY_MDM6600_CMD_BP_SHUTDOWN_REQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) msleep(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) gpiod_set_value_cansleep(reset_gpio, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) dev_info(ddata->dev, "Waiting for power down request to complete.. ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (wait_for_completion_timeout(&ddata->ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) msecs_to_jiffies(5000))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (ddata->status == PHY_MDM6600_STATUS_PANIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) dev_info(ddata->dev, "Powered down OK\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) dev_err(ddata->dev, "Timed out powering down\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) static void phy_mdm6600_deferred_power_on(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) struct phy_mdm6600 *ddata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) ddata = container_of(work, struct phy_mdm6600, bootup_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) error = phy_mdm6600_device_power_on(ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) dev_err(ddata->dev, "Device not functional\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) * USB suspend puts mdm6600 into low power mode. For any n_gsm using apps,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) * we need to keep the modem awake by kicking it's mode0 GPIO. This will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) * keep the modem awake for about 1.2 seconds. When no n_gsm apps are using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) * the modem, runtime PM auto mode can be enabled so modem can enter low
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) * power mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) static void phy_mdm6600_wake_modem(struct phy_mdm6600 *ddata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) struct gpio_desc *mode_gpio0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) mode_gpio0 = ddata->mode_gpios->desc[PHY_MDM6600_MODE0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) gpiod_set_value_cansleep(mode_gpio0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) usleep_range(5, 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) gpiod_set_value_cansleep(mode_gpio0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) if (ddata->awake)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) usleep_range(5, 15);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) msleep(MDM6600_MODEM_WAKE_DELAY_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) static void phy_mdm6600_modem_wake(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) struct phy_mdm6600 *ddata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) ddata = container_of(work, struct phy_mdm6600, modem_wake_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) phy_mdm6600_wake_modem(ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) * The modem does not always stay awake 1.2 seconds after toggling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) * the wake GPIO, and sometimes it idles after about some 600 ms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * making writes time out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) schedule_delayed_work(&ddata->modem_wake_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) msecs_to_jiffies(PHY_MDM6600_WAKE_KICK_MS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) static int __maybe_unused phy_mdm6600_runtime_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) struct phy_mdm6600 *ddata = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) cancel_delayed_work_sync(&ddata->modem_wake_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) ddata->awake = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) static int __maybe_unused phy_mdm6600_runtime_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) struct phy_mdm6600 *ddata = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) phy_mdm6600_modem_wake(&ddata->modem_wake_work.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) ddata->awake = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) static const struct dev_pm_ops phy_mdm6600_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) SET_RUNTIME_PM_OPS(phy_mdm6600_runtime_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) phy_mdm6600_runtime_resume, NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static const struct of_device_id phy_mdm6600_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) { .compatible = "motorola,mapphone-mdm6600", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) MODULE_DEVICE_TABLE(of, phy_mdm6600_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) static int phy_mdm6600_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) struct phy_mdm6600 *ddata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) if (!ddata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) INIT_DELAYED_WORK(&ddata->bootup_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) phy_mdm6600_deferred_power_on);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) INIT_DELAYED_WORK(&ddata->status_work, phy_mdm6600_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) INIT_DELAYED_WORK(&ddata->modem_wake_work, phy_mdm6600_modem_wake);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) init_completion(&ddata->ack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) ddata->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) platform_set_drvdata(pdev, ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) /* Active state selected in phy_mdm6600_power_on() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) error = pinctrl_pm_select_sleep_state(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) dev_warn(ddata->dev, "%s: error with sleep_state: %i\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) error = phy_mdm6600_init_lines(ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) phy_mdm6600_init_irq(ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) schedule_delayed_work(&ddata->bootup_work, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) * See phy_mdm6600_device_power_on(). We should be able
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) * to remove this eventually when ohci-platform can deal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) * with -EPROBE_DEFER.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) msleep(PHY_MDM6600_PHY_DELAY_MS + 500);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) * Enable PM runtime only after PHY has been powered up properly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) * It is currently only needed after USB suspends mdm6600 and n_gsm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) * needs to access the device. We don't want to do this earlier as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) * gpio mode0 pin doubles as mdm6600 wake-up gpio.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) pm_runtime_use_autosuspend(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) pm_runtime_set_autosuspend_delay(ddata->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) MDM6600_MODEM_IDLE_DELAY_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) pm_runtime_enable(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) error = pm_runtime_get_sync(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) dev_warn(ddata->dev, "failed to wake modem: %i\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) pm_runtime_put_noidle(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) ddata->generic_phy = devm_phy_create(ddata->dev, NULL, &gpio_usb_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (IS_ERR(ddata->generic_phy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) error = PTR_ERR(ddata->generic_phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) goto idle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) phy_set_drvdata(ddata->generic_phy, ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) ddata->phy_provider =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) devm_of_phy_provider_register(ddata->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) of_phy_simple_xlate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (IS_ERR(ddata->phy_provider))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) error = PTR_ERR(ddata->phy_provider);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) idle:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) pm_runtime_mark_last_busy(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) pm_runtime_put_autosuspend(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (error < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) phy_mdm6600_device_power_off(ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) static int phy_mdm6600_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) struct phy_mdm6600 *ddata = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) struct gpio_desc *reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) pm_runtime_dont_use_autosuspend(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) pm_runtime_put_sync(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) pm_runtime_disable(ddata->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) if (!ddata->running)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) wait_for_completion_timeout(&ddata->ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) msecs_to_jiffies(PHY_MDM6600_ENABLED_DELAY_MS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) gpiod_set_value_cansleep(reset_gpio, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) phy_mdm6600_device_power_off(ddata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) cancel_delayed_work_sync(&ddata->modem_wake_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) cancel_delayed_work_sync(&ddata->bootup_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) cancel_delayed_work_sync(&ddata->status_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) static struct platform_driver phy_mdm6600_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) .probe = phy_mdm6600_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) .remove = phy_mdm6600_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) .name = "phy-mapphone-mdm6600",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) .pm = &phy_mdm6600_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) .of_match_table = of_match_ptr(phy_mdm6600_id_table),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) module_platform_driver(phy_mdm6600_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) MODULE_ALIAS("platform:gpio_usb");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) MODULE_DESCRIPTION("mdm6600 gpio usb phy driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) MODULE_LICENSE("GPL v2");