root/drivers/phy/motorola/phy-mapphone-mdm6600.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. phy_mdm6600_init
  2. phy_mdm6600_power_on
  3. phy_mdm6600_power_off
  4. phy_mdm6600_cmd
  5. phy_mdm6600_status
  6. phy_mdm6600_irq_thread
  7. phy_mdm6600_wakeirq_thread
  8. phy_mdm6600_init_irq
  9. phy_mdm6600_init_lines
  10. phy_mdm6600_device_power_on
  11. phy_mdm6600_device_power_off
  12. phy_mdm6600_deferred_power_on
  13. phy_mdm6600_wake_modem
  14. phy_mdm6600_modem_wake
  15. phy_mdm6600_runtime_suspend
  16. phy_mdm6600_runtime_resume
  17. phy_mdm6600_probe
  18. phy_mdm6600_remove

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

/* [<][>][^][v][top][bottom][index][help] */