Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Motorola Mapphone MDM6600 modem GPIO controlled USB PHY driver
0004  * Copyright (C) 2018 Tony Lindgren <tony@atomide.com>
0005  */
0006 
0007 #include <linux/delay.h>
0008 #include <linux/err.h>
0009 #include <linux/io.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/module.h>
0012 #include <linux/of.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/slab.h>
0015 
0016 #include <linux/gpio/consumer.h>
0017 #include <linux/of_platform.h>
0018 #include <linux/phy/phy.h>
0019 #include <linux/pinctrl/consumer.h>
0020 
0021 #define PHY_MDM6600_PHY_DELAY_MS    4000    /* PHY enable 2.2s to 3.5s */
0022 #define PHY_MDM6600_ENABLED_DELAY_MS    8000    /* 8s more total for MDM6600 */
0023 #define PHY_MDM6600_WAKE_KICK_MS    600 /* time on after GPIO toggle */
0024 #define MDM6600_MODEM_IDLE_DELAY_MS 1000    /* modem after USB suspend */
0025 #define MDM6600_MODEM_WAKE_DELAY_MS 200 /* modem response after idle */
0026 
0027 enum phy_mdm6600_ctrl_lines {
0028     PHY_MDM6600_ENABLE,         /* USB PHY enable */
0029     PHY_MDM6600_POWER,          /* Device power */
0030     PHY_MDM6600_RESET,          /* Device reset */
0031     PHY_MDM6600_NR_CTRL_LINES,
0032 };
0033 
0034 enum phy_mdm6600_bootmode_lines {
0035     PHY_MDM6600_MODE0,          /* out USB mode0 and OOB wake */
0036     PHY_MDM6600_MODE1,          /* out USB mode1, in OOB wake */
0037     PHY_MDM6600_NR_MODE_LINES,
0038 };
0039 
0040 enum phy_mdm6600_cmd_lines {
0041     PHY_MDM6600_CMD0,
0042     PHY_MDM6600_CMD1,
0043     PHY_MDM6600_CMD2,
0044     PHY_MDM6600_NR_CMD_LINES,
0045 };
0046 
0047 enum phy_mdm6600_status_lines {
0048     PHY_MDM6600_STATUS0,
0049     PHY_MDM6600_STATUS1,
0050     PHY_MDM6600_STATUS2,
0051     PHY_MDM6600_NR_STATUS_LINES,
0052 };
0053 
0054 /*
0055  * MDM6600 command codes. These are based on Motorola Mapphone Linux
0056  * kernel tree.
0057  */
0058 enum phy_mdm6600_cmd {
0059     PHY_MDM6600_CMD_BP_PANIC_ACK,
0060     PHY_MDM6600_CMD_DATA_ONLY_BYPASS,   /* Reroute USB to CPCAP PHY */
0061     PHY_MDM6600_CMD_FULL_BYPASS,        /* Reroute USB to CPCAP PHY */
0062     PHY_MDM6600_CMD_NO_BYPASS,      /* Request normal USB mode */
0063     PHY_MDM6600_CMD_BP_SHUTDOWN_REQ,    /* Request device power off */
0064     PHY_MDM6600_CMD_BP_UNKNOWN_5,
0065     PHY_MDM6600_CMD_BP_UNKNOWN_6,
0066     PHY_MDM6600_CMD_UNDEFINED,
0067 };
0068 
0069 /*
0070  * MDM6600 status codes. These are based on Motorola Mapphone Linux
0071  * kernel tree.
0072  */
0073 enum phy_mdm6600_status {
0074     PHY_MDM6600_STATUS_PANIC,       /* Seems to be really off */
0075     PHY_MDM6600_STATUS_PANIC_BUSY_WAIT,
0076     PHY_MDM6600_STATUS_QC_DLOAD,
0077     PHY_MDM6600_STATUS_RAM_DOWNLOADER,  /* MDM6600 USB flashing mode */
0078     PHY_MDM6600_STATUS_PHONE_CODE_AWAKE,    /* MDM6600 normal USB mode */
0079     PHY_MDM6600_STATUS_PHONE_CODE_ASLEEP,
0080     PHY_MDM6600_STATUS_SHUTDOWN_ACK,
0081     PHY_MDM6600_STATUS_UNDEFINED,
0082 };
0083 
0084 static const char * const
0085 phy_mdm6600_status_name[] = {
0086     "off", "busy", "qc_dl", "ram_dl", "awake",
0087     "asleep", "shutdown", "undefined",
0088 };
0089 
0090 struct phy_mdm6600 {
0091     struct device *dev;
0092     struct phy *generic_phy;
0093     struct phy_provider *phy_provider;
0094     struct gpio_desc *ctrl_gpios[PHY_MDM6600_NR_CTRL_LINES];
0095     struct gpio_descs *mode_gpios;
0096     struct gpio_descs *status_gpios;
0097     struct gpio_descs *cmd_gpios;
0098     struct delayed_work bootup_work;
0099     struct delayed_work status_work;
0100     struct delayed_work modem_wake_work;
0101     struct completion ack;
0102     bool enabled;               /* mdm6600 phy enabled */
0103     bool running;               /* mdm6600 boot done */
0104     bool awake;             /* mdm6600 respnds on n_gsm */
0105     int status;
0106 };
0107 
0108 static int phy_mdm6600_init(struct phy *x)
0109 {
0110     struct phy_mdm6600 *ddata = phy_get_drvdata(x);
0111     struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
0112 
0113     if (!ddata->enabled)
0114         return -EPROBE_DEFER;
0115 
0116     gpiod_set_value_cansleep(enable_gpio, 0);
0117 
0118     return 0;
0119 }
0120 
0121 static int phy_mdm6600_power_on(struct phy *x)
0122 {
0123     struct phy_mdm6600 *ddata = phy_get_drvdata(x);
0124     struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
0125     int error;
0126 
0127     if (!ddata->enabled)
0128         return -ENODEV;
0129 
0130     error = pinctrl_pm_select_default_state(ddata->dev);
0131     if (error)
0132         dev_warn(ddata->dev, "%s: error with default_state: %i\n",
0133              __func__, error);
0134 
0135     gpiod_set_value_cansleep(enable_gpio, 1);
0136 
0137     /* Allow aggressive PM for USB, it's only needed for n_gsm port */
0138     if (pm_runtime_enabled(&x->dev))
0139         phy_pm_runtime_put(x);
0140 
0141     return 0;
0142 }
0143 
0144 static int phy_mdm6600_power_off(struct phy *x)
0145 {
0146     struct phy_mdm6600 *ddata = phy_get_drvdata(x);
0147     struct gpio_desc *enable_gpio = ddata->ctrl_gpios[PHY_MDM6600_ENABLE];
0148     int error;
0149 
0150     if (!ddata->enabled)
0151         return -ENODEV;
0152 
0153     /* Paired with phy_pm_runtime_put() in phy_mdm6600_power_on() */
0154     if (pm_runtime_enabled(&x->dev)) {
0155         error = phy_pm_runtime_get(x);
0156         if (error < 0 && error != -EINPROGRESS)
0157             dev_warn(ddata->dev, "%s: phy_pm_runtime_get: %i\n",
0158                  __func__, error);
0159     }
0160 
0161     gpiod_set_value_cansleep(enable_gpio, 0);
0162 
0163     error = pinctrl_pm_select_sleep_state(ddata->dev);
0164     if (error)
0165         dev_warn(ddata->dev, "%s: error with sleep_state: %i\n",
0166              __func__, error);
0167 
0168     return 0;
0169 }
0170 
0171 static const struct phy_ops gpio_usb_ops = {
0172     .init = phy_mdm6600_init,
0173     .power_on = phy_mdm6600_power_on,
0174     .power_off = phy_mdm6600_power_off,
0175     .owner = THIS_MODULE,
0176 };
0177 
0178 /**
0179  * phy_mdm6600_cmd() - send a command request to mdm6600
0180  * @ddata: device driver data
0181  * @val: value of cmd to be set
0182  *
0183  * Configures the three command request GPIOs to the specified value.
0184  */
0185 static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
0186 {
0187     DECLARE_BITMAP(values, PHY_MDM6600_NR_CMD_LINES);
0188 
0189     values[0] = val;
0190 
0191     gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
0192                        ddata->cmd_gpios->desc,
0193                        ddata->cmd_gpios->info, values);
0194 }
0195 
0196 /**
0197  * phy_mdm6600_status() - read mdm6600 status lines
0198  * @work: work structure
0199  */
0200 static void phy_mdm6600_status(struct work_struct *work)
0201 {
0202     struct phy_mdm6600 *ddata;
0203     struct device *dev;
0204     DECLARE_BITMAP(values, PHY_MDM6600_NR_STATUS_LINES);
0205     int error;
0206 
0207     ddata = container_of(work, struct phy_mdm6600, status_work.work);
0208     dev = ddata->dev;
0209 
0210     error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES,
0211                            ddata->status_gpios->desc,
0212                            ddata->status_gpios->info,
0213                            values);
0214     if (error)
0215         return;
0216 
0217     ddata->status = values[0] & ((1 << PHY_MDM6600_NR_STATUS_LINES) - 1);
0218 
0219     dev_info(dev, "modem status: %i %s\n",
0220          ddata->status,
0221          phy_mdm6600_status_name[ddata->status]);
0222     complete(&ddata->ack);
0223 }
0224 
0225 static irqreturn_t phy_mdm6600_irq_thread(int irq, void *data)
0226 {
0227     struct phy_mdm6600 *ddata = data;
0228 
0229     schedule_delayed_work(&ddata->status_work, msecs_to_jiffies(10));
0230 
0231     return IRQ_HANDLED;
0232 }
0233 
0234 /**
0235  * phy_mdm6600_wakeirq_thread - handle mode1 line OOB wake after booting
0236  * @irq: interrupt
0237  * @data: interrupt handler data
0238  *
0239  * GPIO mode1 is used initially as output to configure the USB boot
0240  * mode for mdm6600. After booting it is used as input for OOB wake
0241  * signal from mdm6600 to the SoC. Just use it for debug info only
0242  * for now.
0243  */
0244 static irqreturn_t phy_mdm6600_wakeirq_thread(int irq, void *data)
0245 {
0246     struct phy_mdm6600 *ddata = data;
0247     struct gpio_desc *mode_gpio1;
0248     int error, wakeup;
0249 
0250     mode_gpio1 = ddata->mode_gpios->desc[PHY_MDM6600_MODE1];
0251     wakeup = gpiod_get_value(mode_gpio1);
0252     if (!wakeup)
0253         return IRQ_NONE;
0254 
0255     dev_dbg(ddata->dev, "OOB wake on mode_gpio1: %i\n", wakeup);
0256     error = pm_runtime_get_sync(ddata->dev);
0257     if (error < 0) {
0258         pm_runtime_put_noidle(ddata->dev);
0259 
0260         return IRQ_NONE;
0261     }
0262 
0263     /* Just wake-up and kick the autosuspend timer */
0264     pm_runtime_mark_last_busy(ddata->dev);
0265     pm_runtime_put_autosuspend(ddata->dev);
0266 
0267     return IRQ_HANDLED;
0268 }
0269 
0270 /**
0271  * phy_mdm6600_init_irq() - initialize mdm6600 status IRQ lines
0272  * @ddata: device driver data
0273  */
0274 static void phy_mdm6600_init_irq(struct phy_mdm6600 *ddata)
0275 {
0276     struct device *dev = ddata->dev;
0277     int i, error, irq;
0278 
0279     for (i = PHY_MDM6600_STATUS0;
0280          i <= PHY_MDM6600_STATUS2; i++) {
0281         struct gpio_desc *gpio = ddata->status_gpios->desc[i];
0282 
0283         irq = gpiod_to_irq(gpio);
0284         if (irq <= 0)
0285             continue;
0286 
0287         error = devm_request_threaded_irq(dev, irq, NULL,
0288                     phy_mdm6600_irq_thread,
0289                     IRQF_TRIGGER_RISING |
0290                     IRQF_TRIGGER_FALLING |
0291                     IRQF_ONESHOT,
0292                     "mdm6600",
0293                     ddata);
0294         if (error)
0295             dev_warn(dev, "no modem status irq%i: %i\n",
0296                  irq, error);
0297     }
0298 }
0299 
0300 struct phy_mdm6600_map {
0301     const char *name;
0302     int direction;
0303 };
0304 
0305 static const struct phy_mdm6600_map
0306 phy_mdm6600_ctrl_gpio_map[PHY_MDM6600_NR_CTRL_LINES] = {
0307     { "enable", GPIOD_OUT_LOW, },       /* low = phy disabled */
0308     { "power", GPIOD_OUT_LOW, },        /* low = off */
0309     { "reset", GPIOD_OUT_HIGH, },       /* high = reset */
0310 };
0311 
0312 /**
0313  * phy_mdm6600_init_lines() - initialize mdm6600 GPIO lines
0314  * @ddata: device driver data
0315  */
0316 static int phy_mdm6600_init_lines(struct phy_mdm6600 *ddata)
0317 {
0318     struct device *dev = ddata->dev;
0319     int i;
0320 
0321     /* MDM6600 control lines */
0322     for (i = 0; i < ARRAY_SIZE(phy_mdm6600_ctrl_gpio_map); i++) {
0323         const struct phy_mdm6600_map *map =
0324             &phy_mdm6600_ctrl_gpio_map[i];
0325         struct gpio_desc **gpio = &ddata->ctrl_gpios[i];
0326 
0327         *gpio = devm_gpiod_get(dev, map->name, map->direction);
0328         if (IS_ERR(*gpio)) {
0329             dev_info(dev, "gpio %s error %li\n",
0330                  map->name, PTR_ERR(*gpio));
0331             return PTR_ERR(*gpio);
0332         }
0333     }
0334 
0335     /* MDM6600 USB start-up mode output lines */
0336     ddata->mode_gpios = devm_gpiod_get_array(dev, "motorola,mode",
0337                          GPIOD_OUT_LOW);
0338     if (IS_ERR(ddata->mode_gpios))
0339         return PTR_ERR(ddata->mode_gpios);
0340 
0341     if (ddata->mode_gpios->ndescs != PHY_MDM6600_NR_MODE_LINES)
0342         return -EINVAL;
0343 
0344     /* MDM6600 status input lines */
0345     ddata->status_gpios = devm_gpiod_get_array(dev, "motorola,status",
0346                            GPIOD_IN);
0347     if (IS_ERR(ddata->status_gpios))
0348         return PTR_ERR(ddata->status_gpios);
0349 
0350     if (ddata->status_gpios->ndescs != PHY_MDM6600_NR_STATUS_LINES)
0351         return -EINVAL;
0352 
0353     /* MDM6600 cmd output lines */
0354     ddata->cmd_gpios = devm_gpiod_get_array(dev, "motorola,cmd",
0355                         GPIOD_OUT_LOW);
0356     if (IS_ERR(ddata->cmd_gpios))
0357         return PTR_ERR(ddata->cmd_gpios);
0358 
0359     if (ddata->cmd_gpios->ndescs != PHY_MDM6600_NR_CMD_LINES)
0360         return -EINVAL;
0361 
0362     return 0;
0363 }
0364 
0365 /**
0366  * phy_mdm6600_device_power_on() - power on mdm6600 device
0367  * @ddata: device driver data
0368  *
0369  * To get the integrated USB phy in MDM6600 takes some hoops. We must ensure
0370  * the shared USB bootmode GPIOs are configured, then request modem start-up,
0371  * reset and power-up.. And then we need to recycle the shared USB bootmode
0372  * GPIOs as they are also used for Out of Band (OOB) wake for the USB and
0373  * TS 27.010 serial mux.
0374  */
0375 static int phy_mdm6600_device_power_on(struct phy_mdm6600 *ddata)
0376 {
0377     struct gpio_desc *mode_gpio0, *mode_gpio1, *reset_gpio, *power_gpio;
0378     int error = 0, wakeirq;
0379 
0380     mode_gpio0 = ddata->mode_gpios->desc[PHY_MDM6600_MODE0];
0381     mode_gpio1 = ddata->mode_gpios->desc[PHY_MDM6600_MODE1];
0382     reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
0383     power_gpio = ddata->ctrl_gpios[PHY_MDM6600_POWER];
0384 
0385     /*
0386      * Shared GPIOs must be low for normal USB mode. After booting
0387      * they are used for OOB wake signaling. These can be also used
0388      * to configure USB flashing mode later on based on a module
0389      * parameter.
0390      */
0391     gpiod_set_value_cansleep(mode_gpio0, 0);
0392     gpiod_set_value_cansleep(mode_gpio1, 0);
0393 
0394     /* Request start-up mode */
0395     phy_mdm6600_cmd(ddata, PHY_MDM6600_CMD_NO_BYPASS);
0396 
0397     /* Request a reset first */
0398     gpiod_set_value_cansleep(reset_gpio, 0);
0399     msleep(100);
0400 
0401     /* Toggle power GPIO to request mdm6600 to start */
0402     gpiod_set_value_cansleep(power_gpio, 1);
0403     msleep(100);
0404     gpiod_set_value_cansleep(power_gpio, 0);
0405 
0406     /*
0407      * Looks like the USB PHY needs between 2.2 to 4 seconds.
0408      * If we try to use it before that, we will get L3 errors
0409      * from omap-usb-host trying to access the PHY. See also
0410      * phy_mdm6600_init() for -EPROBE_DEFER.
0411      */
0412     msleep(PHY_MDM6600_PHY_DELAY_MS);
0413     ddata->enabled = true;
0414 
0415     /* Booting up the rest of MDM6600 will take total about 8 seconds */
0416     dev_info(ddata->dev, "Waiting for power up request to complete..\n");
0417     if (wait_for_completion_timeout(&ddata->ack,
0418             msecs_to_jiffies(PHY_MDM6600_ENABLED_DELAY_MS))) {
0419         if (ddata->status > PHY_MDM6600_STATUS_PANIC &&
0420             ddata->status < PHY_MDM6600_STATUS_SHUTDOWN_ACK)
0421             dev_info(ddata->dev, "Powered up OK\n");
0422     } else {
0423         ddata->enabled = false;
0424         error = -ETIMEDOUT;
0425         dev_err(ddata->dev, "Timed out powering up\n");
0426     }
0427 
0428     /* Reconfigure mode1 GPIO as input for OOB wake */
0429     gpiod_direction_input(mode_gpio1);
0430 
0431     wakeirq = gpiod_to_irq(mode_gpio1);
0432     if (wakeirq <= 0)
0433         return wakeirq;
0434 
0435     error = devm_request_threaded_irq(ddata->dev, wakeirq, NULL,
0436                       phy_mdm6600_wakeirq_thread,
0437                       IRQF_TRIGGER_RISING |
0438                       IRQF_TRIGGER_FALLING |
0439                       IRQF_ONESHOT,
0440                       "mdm6600-wake",
0441                       ddata);
0442     if (error)
0443         dev_warn(ddata->dev, "no modem wakeirq irq%i: %i\n",
0444              wakeirq, error);
0445 
0446     ddata->running = true;
0447 
0448     return error;
0449 }
0450 
0451 /**
0452  * phy_mdm6600_device_power_off() - power off mdm6600 device
0453  * @ddata: device driver data
0454  */
0455 static void phy_mdm6600_device_power_off(struct phy_mdm6600 *ddata)
0456 {
0457     struct gpio_desc *reset_gpio =
0458         ddata->ctrl_gpios[PHY_MDM6600_RESET];
0459 
0460     ddata->enabled = false;
0461     phy_mdm6600_cmd(ddata, PHY_MDM6600_CMD_BP_SHUTDOWN_REQ);
0462     msleep(100);
0463 
0464     gpiod_set_value_cansleep(reset_gpio, 1);
0465 
0466     dev_info(ddata->dev, "Waiting for power down request to complete.. ");
0467     if (wait_for_completion_timeout(&ddata->ack,
0468                     msecs_to_jiffies(5000))) {
0469         if (ddata->status == PHY_MDM6600_STATUS_PANIC)
0470             dev_info(ddata->dev, "Powered down OK\n");
0471     } else {
0472         dev_err(ddata->dev, "Timed out powering down\n");
0473     }
0474 }
0475 
0476 static void phy_mdm6600_deferred_power_on(struct work_struct *work)
0477 {
0478     struct phy_mdm6600 *ddata;
0479     int error;
0480 
0481     ddata = container_of(work, struct phy_mdm6600, bootup_work.work);
0482 
0483     error = phy_mdm6600_device_power_on(ddata);
0484     if (error)
0485         dev_err(ddata->dev, "Device not functional\n");
0486 }
0487 
0488 /*
0489  * USB suspend puts mdm6600 into low power mode. For any n_gsm using apps,
0490  * we need to keep the modem awake by kicking it's mode0 GPIO. This will
0491  * keep the modem awake for about 1.2 seconds. When no n_gsm apps are using
0492  * the modem, runtime PM auto mode can be enabled so modem can enter low
0493  * power mode.
0494  */
0495 static void phy_mdm6600_wake_modem(struct phy_mdm6600 *ddata)
0496 {
0497     struct gpio_desc *mode_gpio0;
0498 
0499     mode_gpio0 = ddata->mode_gpios->desc[PHY_MDM6600_MODE0];
0500     gpiod_set_value_cansleep(mode_gpio0, 1);
0501     usleep_range(5, 15);
0502     gpiod_set_value_cansleep(mode_gpio0, 0);
0503     if (ddata->awake)
0504         usleep_range(5, 15);
0505     else
0506         msleep(MDM6600_MODEM_WAKE_DELAY_MS);
0507 }
0508 
0509 static void phy_mdm6600_modem_wake(struct work_struct *work)
0510 {
0511     struct phy_mdm6600 *ddata;
0512 
0513     ddata = container_of(work, struct phy_mdm6600, modem_wake_work.work);
0514     phy_mdm6600_wake_modem(ddata);
0515 
0516     /*
0517      * The modem does not always stay awake 1.2 seconds after toggling
0518      * the wake GPIO, and sometimes it idles after about some 600 ms
0519      * making writes time out.
0520      */
0521     schedule_delayed_work(&ddata->modem_wake_work,
0522                   msecs_to_jiffies(PHY_MDM6600_WAKE_KICK_MS));
0523 }
0524 
0525 static int __maybe_unused phy_mdm6600_runtime_suspend(struct device *dev)
0526 {
0527     struct phy_mdm6600 *ddata = dev_get_drvdata(dev);
0528 
0529     cancel_delayed_work_sync(&ddata->modem_wake_work);
0530     ddata->awake = false;
0531 
0532     return 0;
0533 }
0534 
0535 static int __maybe_unused phy_mdm6600_runtime_resume(struct device *dev)
0536 {
0537     struct phy_mdm6600 *ddata = dev_get_drvdata(dev);
0538 
0539     phy_mdm6600_modem_wake(&ddata->modem_wake_work.work);
0540     ddata->awake = true;
0541 
0542     return 0;
0543 }
0544 
0545 static const struct dev_pm_ops phy_mdm6600_pm_ops = {
0546     SET_RUNTIME_PM_OPS(phy_mdm6600_runtime_suspend,
0547                phy_mdm6600_runtime_resume, NULL)
0548 };
0549 
0550 static const struct of_device_id phy_mdm6600_id_table[] = {
0551     { .compatible = "motorola,mapphone-mdm6600", },
0552     {},
0553 };
0554 MODULE_DEVICE_TABLE(of, phy_mdm6600_id_table);
0555 
0556 static int phy_mdm6600_probe(struct platform_device *pdev)
0557 {
0558     struct phy_mdm6600 *ddata;
0559     int error;
0560 
0561     ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
0562     if (!ddata)
0563         return -ENOMEM;
0564 
0565     INIT_DELAYED_WORK(&ddata->bootup_work,
0566               phy_mdm6600_deferred_power_on);
0567     INIT_DELAYED_WORK(&ddata->status_work, phy_mdm6600_status);
0568     INIT_DELAYED_WORK(&ddata->modem_wake_work, phy_mdm6600_modem_wake);
0569     init_completion(&ddata->ack);
0570 
0571     ddata->dev = &pdev->dev;
0572     platform_set_drvdata(pdev, ddata);
0573 
0574     /* Active state selected in phy_mdm6600_power_on() */
0575     error = pinctrl_pm_select_sleep_state(ddata->dev);
0576     if (error)
0577         dev_warn(ddata->dev, "%s: error with sleep_state: %i\n",
0578              __func__, error);
0579 
0580     error = phy_mdm6600_init_lines(ddata);
0581     if (error)
0582         return error;
0583 
0584     phy_mdm6600_init_irq(ddata);
0585     schedule_delayed_work(&ddata->bootup_work, 0);
0586 
0587     /*
0588      * See phy_mdm6600_device_power_on(). We should be able
0589      * to remove this eventually when ohci-platform can deal
0590      * with -EPROBE_DEFER.
0591      */
0592     msleep(PHY_MDM6600_PHY_DELAY_MS + 500);
0593 
0594     /*
0595      * Enable PM runtime only after PHY has been powered up properly.
0596      * It is currently only needed after USB suspends mdm6600 and n_gsm
0597      * needs to access the device. We don't want to do this earlier as
0598      * gpio mode0 pin doubles as mdm6600 wake-up gpio.
0599      */
0600     pm_runtime_use_autosuspend(ddata->dev);
0601     pm_runtime_set_autosuspend_delay(ddata->dev,
0602                      MDM6600_MODEM_IDLE_DELAY_MS);
0603     pm_runtime_enable(ddata->dev);
0604     error = pm_runtime_get_sync(ddata->dev);
0605     if (error < 0) {
0606         dev_warn(ddata->dev, "failed to wake modem: %i\n", error);
0607         pm_runtime_put_noidle(ddata->dev);
0608         goto cleanup;
0609     }
0610 
0611     ddata->generic_phy = devm_phy_create(ddata->dev, NULL, &gpio_usb_ops);
0612     if (IS_ERR(ddata->generic_phy)) {
0613         error = PTR_ERR(ddata->generic_phy);
0614         goto idle;
0615     }
0616 
0617     phy_set_drvdata(ddata->generic_phy, ddata);
0618 
0619     ddata->phy_provider =
0620         devm_of_phy_provider_register(ddata->dev,
0621                           of_phy_simple_xlate);
0622     if (IS_ERR(ddata->phy_provider))
0623         error = PTR_ERR(ddata->phy_provider);
0624 
0625 idle:
0626     pm_runtime_mark_last_busy(ddata->dev);
0627     pm_runtime_put_autosuspend(ddata->dev);
0628 
0629 cleanup:
0630     if (error < 0)
0631         phy_mdm6600_device_power_off(ddata);
0632     pm_runtime_disable(ddata->dev);
0633     pm_runtime_dont_use_autosuspend(ddata->dev);
0634     return error;
0635 }
0636 
0637 static int phy_mdm6600_remove(struct platform_device *pdev)
0638 {
0639     struct phy_mdm6600 *ddata = platform_get_drvdata(pdev);
0640     struct gpio_desc *reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
0641 
0642     pm_runtime_dont_use_autosuspend(ddata->dev);
0643     pm_runtime_put_sync(ddata->dev);
0644     pm_runtime_disable(ddata->dev);
0645 
0646     if (!ddata->running)
0647         wait_for_completion_timeout(&ddata->ack,
0648             msecs_to_jiffies(PHY_MDM6600_ENABLED_DELAY_MS));
0649 
0650     gpiod_set_value_cansleep(reset_gpio, 1);
0651     phy_mdm6600_device_power_off(ddata);
0652 
0653     cancel_delayed_work_sync(&ddata->modem_wake_work);
0654     cancel_delayed_work_sync(&ddata->bootup_work);
0655     cancel_delayed_work_sync(&ddata->status_work);
0656 
0657     return 0;
0658 }
0659 
0660 static struct platform_driver phy_mdm6600_driver = {
0661     .probe = phy_mdm6600_probe,
0662     .remove = phy_mdm6600_remove,
0663     .driver = {
0664         .name = "phy-mapphone-mdm6600",
0665         .pm = &phy_mdm6600_pm_ops,
0666         .of_match_table = of_match_ptr(phy_mdm6600_id_table),
0667     },
0668 };
0669 
0670 module_platform_driver(phy_mdm6600_driver);
0671 
0672 MODULE_ALIAS("platform:gpio_usb");
0673 MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
0674 MODULE_DESCRIPTION("mdm6600 gpio usb phy driver");
0675 MODULE_LICENSE("GPL v2");