17fa60654SVaibhav Hiremath /* 27fa60654SVaibhav Hiremath * Arche Platform driver to enable Unipro link. 37fa60654SVaibhav Hiremath * 47fa60654SVaibhav Hiremath * Copyright 2014-2015 Google Inc. 57fa60654SVaibhav Hiremath * Copyright 2014-2015 Linaro Ltd. 67fa60654SVaibhav Hiremath * 77fa60654SVaibhav Hiremath * Released under the GPLv2 only. 87fa60654SVaibhav Hiremath */ 97fa60654SVaibhav Hiremath 107fa60654SVaibhav Hiremath #include <linux/clk.h> 11a463fc15SVaibhav Hiremath #include <linux/delay.h> 123b858df0SViresh Kumar #include <linux/gpio.h> 133b858df0SViresh Kumar #include <linux/init.h> 143b858df0SViresh Kumar #include <linux/module.h> 157fa60654SVaibhav Hiremath #include <linux/of_gpio.h> 163b858df0SViresh Kumar #include <linux/of_platform.h> 177fa60654SVaibhav Hiremath #include <linux/pinctrl/consumer.h> 183b858df0SViresh Kumar #include <linux/platform_device.h> 193b858df0SViresh Kumar #include <linux/pm.h> 201e5dd1f8SGreg Kroah-Hartman #include "arche_platform.h" 217fa60654SVaibhav Hiremath 22ad4d3f95SVaibhav Hiremath #include <linux/usb/usb3613.h> 23ad4d3f95SVaibhav Hiremath 247fa60654SVaibhav Hiremath struct arche_platform_drvdata { 257fa60654SVaibhav Hiremath /* Control GPIO signals to and from AP <=> SVC */ 267fa60654SVaibhav Hiremath int svc_reset_gpio; 277fa60654SVaibhav Hiremath bool is_reset_act_hi; 287fa60654SVaibhav Hiremath int svc_sysboot_gpio; 29a463fc15SVaibhav Hiremath int wake_detect_gpio; /* bi-dir,maps to WAKE_MOD & WAKE_FRAME signals */ 307fa60654SVaibhav Hiremath 31e74d04a5SVaibhav Hiremath enum arche_platform_state state; 32e74d04a5SVaibhav Hiremath 337fa60654SVaibhav Hiremath unsigned int svc_refclk_req; 347fa60654SVaibhav Hiremath struct clk *svc_ref_clk; 357fa60654SVaibhav Hiremath 367fa60654SVaibhav Hiremath struct pinctrl *pinctrl; 377fa60654SVaibhav Hiremath struct pinctrl_state *pin_default; 387fa60654SVaibhav Hiremath 397fa60654SVaibhav Hiremath int num_apbs; 40a463fc15SVaibhav Hiremath 41a463fc15SVaibhav Hiremath struct delayed_work delayed_work; 42a463fc15SVaibhav Hiremath struct device *dev; 437fa60654SVaibhav Hiremath }; 447fa60654SVaibhav Hiremath 457fa60654SVaibhav Hiremath static inline void svc_reset_onoff(unsigned int gpio, bool onoff) 467fa60654SVaibhav Hiremath { 477fa60654SVaibhav Hiremath gpio_set_value(gpio, onoff); 487fa60654SVaibhav Hiremath } 497fa60654SVaibhav Hiremath 50fd60ac58SVaibhav Hiremath static int apb_fw_flashing_state(struct device *dev, void *data) 51fd60ac58SVaibhav Hiremath { 52fd60ac58SVaibhav Hiremath int ret; 53fd60ac58SVaibhav Hiremath 54fd60ac58SVaibhav Hiremath ret = apb_ctrl_fw_flashing(dev); 55fd60ac58SVaibhav Hiremath if (ret) 56fd60ac58SVaibhav Hiremath dev_warn(dev, "failed to switch to fw flashing state\n"); 57fd60ac58SVaibhav Hiremath 58fd60ac58SVaibhav Hiremath /*Child nodes are independent, so do not exit coldboot operation */ 59fd60ac58SVaibhav Hiremath return 0; 60fd60ac58SVaibhav Hiremath } 61fd60ac58SVaibhav Hiremath 62fd60ac58SVaibhav Hiremath static int apb_poweroff(struct device *dev, void *data) 63fd60ac58SVaibhav Hiremath { 64fd60ac58SVaibhav Hiremath apb_ctrl_poweroff(dev); 65fd60ac58SVaibhav Hiremath 66fd60ac58SVaibhav Hiremath return 0; 67fd60ac58SVaibhav Hiremath } 68fd60ac58SVaibhav Hiremath 69a463fc15SVaibhav Hiremath /** 70db5a3bcaSVaibhav Hiremath * hub_conf_delayed_work - Configures USB3613 device to HUB mode 71db5a3bcaSVaibhav Hiremath * 72db5a3bcaSVaibhav Hiremath * The idea here is to split the APB coldboot operation with slow HUB configuration, 73db5a3bcaSVaibhav Hiremath * so that driver response to wake/detect event can be met. 74db5a3bcaSVaibhav Hiremath * So expectation is, once code reaches here, means initial unipro linkup 75db5a3bcaSVaibhav Hiremath * between APB<->Switch was successful, so now just take it to AP. 76a463fc15SVaibhav Hiremath */ 77db5a3bcaSVaibhav Hiremath static void hub_conf_delayed_work(struct work_struct *work) 78a463fc15SVaibhav Hiremath { 79a463fc15SVaibhav Hiremath struct arche_platform_drvdata *arche_pdata = 80a463fc15SVaibhav Hiremath container_of(work, struct arche_platform_drvdata, delayed_work.work); 81ad4d3f95SVaibhav Hiremath 82ad4d3f95SVaibhav Hiremath /* Enable HUB3613 into HUB mode. */ 83ad4d3f95SVaibhav Hiremath if (usb3613_hub_mode_ctrl(true)) 84ad4d3f95SVaibhav Hiremath dev_warn(arche_pdata->dev, "failed to control hub device\n"); 85a463fc15SVaibhav Hiremath } 86a463fc15SVaibhav Hiremath 87758ca99dSVaibhav Hiremath static int arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdata) 88758ca99dSVaibhav Hiremath { 89758ca99dSVaibhav Hiremath int ret; 90758ca99dSVaibhav Hiremath 91599159b6SVaibhav Hiremath if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE) 92599159b6SVaibhav Hiremath return 0; 93599159b6SVaibhav Hiremath 94758ca99dSVaibhav Hiremath dev_info(arche_pdata->dev, "Booting from cold boot state\n"); 95758ca99dSVaibhav Hiremath 96758ca99dSVaibhav Hiremath svc_reset_onoff(arche_pdata->svc_reset_gpio, 97758ca99dSVaibhav Hiremath arche_pdata->is_reset_act_hi); 98758ca99dSVaibhav Hiremath 99758ca99dSVaibhav Hiremath gpio_set_value(arche_pdata->svc_sysboot_gpio, 0); 100758ca99dSVaibhav Hiremath usleep_range(100, 200); 101758ca99dSVaibhav Hiremath 102758ca99dSVaibhav Hiremath ret = clk_prepare_enable(arche_pdata->svc_ref_clk); 103758ca99dSVaibhav Hiremath if (ret) { 104758ca99dSVaibhav Hiremath dev_err(arche_pdata->dev, "failed to enable svc_ref_clk: %d\n", 105758ca99dSVaibhav Hiremath ret); 106758ca99dSVaibhav Hiremath return ret; 107758ca99dSVaibhav Hiremath } 108758ca99dSVaibhav Hiremath 109758ca99dSVaibhav Hiremath /* bring SVC out of reset */ 110758ca99dSVaibhav Hiremath svc_reset_onoff(arche_pdata->svc_reset_gpio, 111758ca99dSVaibhav Hiremath !arche_pdata->is_reset_act_hi); 112758ca99dSVaibhav Hiremath 113e74d04a5SVaibhav Hiremath arche_pdata->state = ARCHE_PLATFORM_STATE_ACTIVE; 114e74d04a5SVaibhav Hiremath 115758ca99dSVaibhav Hiremath return 0; 116758ca99dSVaibhav Hiremath } 117758ca99dSVaibhav Hiremath 1187691fed2SVaibhav Hiremath static void arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_pdata) 1197691fed2SVaibhav Hiremath { 120599159b6SVaibhav Hiremath if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING) 121599159b6SVaibhav Hiremath return; 122599159b6SVaibhav Hiremath 1237691fed2SVaibhav Hiremath dev_info(arche_pdata->dev, "Switching to FW flashing state\n"); 1247691fed2SVaibhav Hiremath 1257691fed2SVaibhav Hiremath svc_reset_onoff(arche_pdata->svc_reset_gpio, 1267691fed2SVaibhav Hiremath arche_pdata->is_reset_act_hi); 1277691fed2SVaibhav Hiremath 1287691fed2SVaibhav Hiremath gpio_set_value(arche_pdata->svc_sysboot_gpio, 1); 1297691fed2SVaibhav Hiremath 1307691fed2SVaibhav Hiremath usleep_range(100, 200); 1317691fed2SVaibhav Hiremath svc_reset_onoff(arche_pdata->svc_reset_gpio, 1327691fed2SVaibhav Hiremath !arche_pdata->is_reset_act_hi); 1337691fed2SVaibhav Hiremath 1347691fed2SVaibhav Hiremath arche_pdata->state = ARCHE_PLATFORM_STATE_FW_FLASHING; 1357691fed2SVaibhav Hiremath 1367691fed2SVaibhav Hiremath } 1377691fed2SVaibhav Hiremath 1385993e2bfSVaibhav Hiremath static void arche_platform_poweroff_seq(struct arche_platform_drvdata *arche_pdata) 1397fa60654SVaibhav Hiremath { 140599159b6SVaibhav Hiremath if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF) 141599159b6SVaibhav Hiremath return; 142599159b6SVaibhav Hiremath 14325847ee7SVaibhav Hiremath /* If in fw_flashing mode, then no need to repeate things again */ 14425847ee7SVaibhav Hiremath if (arche_pdata->state != ARCHE_PLATFORM_STATE_FW_FLASHING) { 145b4c95fcaSVaibhav Hiremath /* Send disconnect/detach event to SVC */ 146b4c95fcaSVaibhav Hiremath gpio_set_value(arche_pdata->wake_detect_gpio, 0); 147b4c95fcaSVaibhav Hiremath usleep_range(100, 200); 148b4c95fcaSVaibhav Hiremath 149d8b16338SVaibhav Hiremath clk_disable_unprepare(arche_pdata->svc_ref_clk); 15025847ee7SVaibhav Hiremath } 15125847ee7SVaibhav Hiremath 1527fa60654SVaibhav Hiremath /* As part of exit, put APB back in reset state */ 1537fa60654SVaibhav Hiremath svc_reset_onoff(arche_pdata->svc_reset_gpio, 1547fa60654SVaibhav Hiremath arche_pdata->is_reset_act_hi); 155e74d04a5SVaibhav Hiremath 156e74d04a5SVaibhav Hiremath arche_pdata->state = ARCHE_PLATFORM_STATE_OFF; 1577fa60654SVaibhav Hiremath } 1587fa60654SVaibhav Hiremath 1592923c58eSVaibhav Hiremath static ssize_t state_store(struct device *dev, 1602923c58eSVaibhav Hiremath struct device_attribute *attr, const char *buf, size_t count) 1612923c58eSVaibhav Hiremath { 1622923c58eSVaibhav Hiremath struct platform_device *pdev = to_platform_device(dev); 1632923c58eSVaibhav Hiremath struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev); 1642923c58eSVaibhav Hiremath int ret = 0; 1652923c58eSVaibhav Hiremath 1662923c58eSVaibhav Hiremath if (sysfs_streq(buf, "off")) { 1672923c58eSVaibhav Hiremath if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF) 1682923c58eSVaibhav Hiremath return count; 1692923c58eSVaibhav Hiremath 170fd60ac58SVaibhav Hiremath /* If SVC goes down, bring down APB's as well */ 171fd60ac58SVaibhav Hiremath device_for_each_child(arche_pdata->dev, NULL, apb_poweroff); 172fd60ac58SVaibhav Hiremath 1732923c58eSVaibhav Hiremath arche_platform_poweroff_seq(arche_pdata); 174ad4d3f95SVaibhav Hiremath 175ad4d3f95SVaibhav Hiremath ret = usb3613_hub_mode_ctrl(false); 176ad4d3f95SVaibhav Hiremath if (ret) 177ad4d3f95SVaibhav Hiremath dev_warn(arche_pdata->dev, "failed to control hub device\n"); 178ad4d3f95SVaibhav Hiremath /* TODO: Should we do anything more here ?? */ 1792923c58eSVaibhav Hiremath } else if (sysfs_streq(buf, "active")) { 1802923c58eSVaibhav Hiremath if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE) 1812923c58eSVaibhav Hiremath return count; 1822923c58eSVaibhav Hiremath 1832923c58eSVaibhav Hiremath ret = arche_platform_coldboot_seq(arche_pdata); 1842923c58eSVaibhav Hiremath } else if (sysfs_streq(buf, "standby")) { 1852923c58eSVaibhav Hiremath if (arche_pdata->state == ARCHE_PLATFORM_STATE_STANDBY) 1862923c58eSVaibhav Hiremath return count; 1872923c58eSVaibhav Hiremath 1882923c58eSVaibhav Hiremath dev_warn(arche_pdata->dev, "standby state not supported\n"); 1897691fed2SVaibhav Hiremath } else if (sysfs_streq(buf, "fw_flashing")) { 1907691fed2SVaibhav Hiremath if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING) 1917691fed2SVaibhav Hiremath return count; 1927691fed2SVaibhav Hiremath 1937691fed2SVaibhav Hiremath /* First we want to make sure we power off everything 1947691fed2SVaibhav Hiremath * and then enter FW flashing state */ 195fd60ac58SVaibhav Hiremath device_for_each_child(arche_pdata->dev, NULL, apb_poweroff); 196fd60ac58SVaibhav Hiremath 1977691fed2SVaibhav Hiremath arche_platform_poweroff_seq(arche_pdata); 198fd60ac58SVaibhav Hiremath 199ad4d3f95SVaibhav Hiremath ret = usb3613_hub_mode_ctrl(false); 200ad4d3f95SVaibhav Hiremath if (ret) 201ad4d3f95SVaibhav Hiremath dev_warn(arche_pdata->dev, "failed to control hub device\n"); 202ad4d3f95SVaibhav Hiremath /* TODO: Should we do anything more here ?? */ 203ad4d3f95SVaibhav Hiremath 2047691fed2SVaibhav Hiremath arche_platform_fw_flashing_seq(arche_pdata); 205fd60ac58SVaibhav Hiremath 206fd60ac58SVaibhav Hiremath device_for_each_child(arche_pdata->dev, NULL, apb_fw_flashing_state); 2072923c58eSVaibhav Hiremath } else { 2082923c58eSVaibhav Hiremath dev_err(arche_pdata->dev, "unknown state\n"); 2092923c58eSVaibhav Hiremath ret = -EINVAL; 2102923c58eSVaibhav Hiremath } 2112923c58eSVaibhav Hiremath 2122923c58eSVaibhav Hiremath return ret ? ret : count; 2132923c58eSVaibhav Hiremath } 2142923c58eSVaibhav Hiremath 2152923c58eSVaibhav Hiremath static ssize_t state_show(struct device *dev, 2162923c58eSVaibhav Hiremath struct device_attribute *attr, char *buf) 2172923c58eSVaibhav Hiremath { 2182923c58eSVaibhav Hiremath struct arche_platform_drvdata *arche_pdata = dev_get_drvdata(dev); 2192923c58eSVaibhav Hiremath 2202923c58eSVaibhav Hiremath switch (arche_pdata->state) { 2212923c58eSVaibhav Hiremath case ARCHE_PLATFORM_STATE_OFF: 2222923c58eSVaibhav Hiremath return sprintf(buf, "off\n"); 2232923c58eSVaibhav Hiremath case ARCHE_PLATFORM_STATE_ACTIVE: 2242923c58eSVaibhav Hiremath return sprintf(buf, "active\n"); 2252923c58eSVaibhav Hiremath case ARCHE_PLATFORM_STATE_STANDBY: 2262923c58eSVaibhav Hiremath return sprintf(buf, "standby\n"); 2277691fed2SVaibhav Hiremath case ARCHE_PLATFORM_STATE_FW_FLASHING: 2287691fed2SVaibhav Hiremath return sprintf(buf, "fw_flashing\n"); 2292923c58eSVaibhav Hiremath default: 2302923c58eSVaibhav Hiremath return sprintf(buf, "unknown state\n"); 2312923c58eSVaibhav Hiremath } 2322923c58eSVaibhav Hiremath } 2332923c58eSVaibhav Hiremath 2342923c58eSVaibhav Hiremath static DEVICE_ATTR_RW(state); 2352923c58eSVaibhav Hiremath 2367fa60654SVaibhav Hiremath static int arche_platform_probe(struct platform_device *pdev) 2377fa60654SVaibhav Hiremath { 2387fa60654SVaibhav Hiremath struct arche_platform_drvdata *arche_pdata; 2397fa60654SVaibhav Hiremath struct device *dev = &pdev->dev; 2407fa60654SVaibhav Hiremath struct device_node *np = dev->of_node; 2417fa60654SVaibhav Hiremath int ret; 2427fa60654SVaibhav Hiremath 2437fa60654SVaibhav Hiremath arche_pdata = devm_kzalloc(&pdev->dev, sizeof(*arche_pdata), GFP_KERNEL); 2447fa60654SVaibhav Hiremath if (!arche_pdata) 2457fa60654SVaibhav Hiremath return -ENOMEM; 2467fa60654SVaibhav Hiremath 2477fa60654SVaibhav Hiremath /* setup svc reset gpio */ 2487fa60654SVaibhav Hiremath arche_pdata->is_reset_act_hi = of_property_read_bool(np, 2497fa60654SVaibhav Hiremath "svc,reset-active-high"); 2507fa60654SVaibhav Hiremath arche_pdata->svc_reset_gpio = of_get_named_gpio(np, "svc,reset-gpio", 0); 2517fa60654SVaibhav Hiremath if (arche_pdata->svc_reset_gpio < 0) { 2527fa60654SVaibhav Hiremath dev_err(dev, "failed to get reset-gpio\n"); 253f1f251b5SViresh Kumar return arche_pdata->svc_reset_gpio; 2547fa60654SVaibhav Hiremath } 2557fa60654SVaibhav Hiremath ret = devm_gpio_request(dev, arche_pdata->svc_reset_gpio, "svc-reset"); 2567fa60654SVaibhav Hiremath if (ret) { 2577fa60654SVaibhav Hiremath dev_err(dev, "failed to request svc-reset gpio:%d\n", ret); 2587fa60654SVaibhav Hiremath return ret; 2597fa60654SVaibhav Hiremath } 2607fa60654SVaibhav Hiremath ret = gpio_direction_output(arche_pdata->svc_reset_gpio, 2617fa60654SVaibhav Hiremath arche_pdata->is_reset_act_hi); 2627fa60654SVaibhav Hiremath if (ret) { 2637fa60654SVaibhav Hiremath dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret); 2647fa60654SVaibhav Hiremath return ret; 2657fa60654SVaibhav Hiremath } 266e74d04a5SVaibhav Hiremath arche_pdata->state = ARCHE_PLATFORM_STATE_OFF; 2677fa60654SVaibhav Hiremath 2687fa60654SVaibhav Hiremath arche_pdata->svc_sysboot_gpio = of_get_named_gpio(np, 2697fa60654SVaibhav Hiremath "svc,sysboot-gpio", 0); 2707fa60654SVaibhav Hiremath if (arche_pdata->svc_sysboot_gpio < 0) { 2717fa60654SVaibhav Hiremath dev_err(dev, "failed to get sysboot gpio\n"); 272f1f251b5SViresh Kumar return arche_pdata->svc_sysboot_gpio; 2737fa60654SVaibhav Hiremath } 2747fa60654SVaibhav Hiremath ret = devm_gpio_request(dev, arche_pdata->svc_sysboot_gpio, "sysboot0"); 2757fa60654SVaibhav Hiremath if (ret) { 2767fa60654SVaibhav Hiremath dev_err(dev, "failed to request sysboot0 gpio:%d\n", ret); 2777fa60654SVaibhav Hiremath return ret; 2787fa60654SVaibhav Hiremath } 2797fa60654SVaibhav Hiremath ret = gpio_direction_output(arche_pdata->svc_sysboot_gpio, 0); 2807fa60654SVaibhav Hiremath if (ret) { 2817fa60654SVaibhav Hiremath dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret); 2827fa60654SVaibhav Hiremath return ret; 2837fa60654SVaibhav Hiremath } 2847fa60654SVaibhav Hiremath 2857fa60654SVaibhav Hiremath /* setup the clock request gpio first */ 2867fa60654SVaibhav Hiremath arche_pdata->svc_refclk_req = of_get_named_gpio(np, 2877fa60654SVaibhav Hiremath "svc,refclk-req-gpio", 0); 2887fa60654SVaibhav Hiremath if (arche_pdata->svc_refclk_req < 0) { 2897fa60654SVaibhav Hiremath dev_err(dev, "failed to get svc clock-req gpio\n"); 290f1f251b5SViresh Kumar return arche_pdata->svc_refclk_req; 2917fa60654SVaibhav Hiremath } 2927fa60654SVaibhav Hiremath ret = devm_gpio_request(dev, arche_pdata->svc_refclk_req, "svc-clk-req"); 2937fa60654SVaibhav Hiremath if (ret) { 2947fa60654SVaibhav Hiremath dev_err(dev, "failed to request svc-clk-req gpio: %d\n", ret); 2957fa60654SVaibhav Hiremath return ret; 2967fa60654SVaibhav Hiremath } 2977fa60654SVaibhav Hiremath ret = gpio_direction_input(arche_pdata->svc_refclk_req); 2987fa60654SVaibhav Hiremath if (ret) { 2997fa60654SVaibhav Hiremath dev_err(dev, "failed to set svc-clk-req gpio dir :%d\n", ret); 3007fa60654SVaibhav Hiremath return ret; 3017fa60654SVaibhav Hiremath } 3027fa60654SVaibhav Hiremath 3037fa60654SVaibhav Hiremath /* setup refclk2 to follow the pin */ 3047fa60654SVaibhav Hiremath arche_pdata->svc_ref_clk = devm_clk_get(dev, "svc_ref_clk"); 3057fa60654SVaibhav Hiremath if (IS_ERR(arche_pdata->svc_ref_clk)) { 3067fa60654SVaibhav Hiremath ret = PTR_ERR(arche_pdata->svc_ref_clk); 3077fa60654SVaibhav Hiremath dev_err(dev, "failed to get svc_ref_clk: %d\n", ret); 3087fa60654SVaibhav Hiremath return ret; 3097fa60654SVaibhav Hiremath } 3107fa60654SVaibhav Hiremath 3117fa60654SVaibhav Hiremath platform_set_drvdata(pdev, arche_pdata); 3127fa60654SVaibhav Hiremath 3137fa60654SVaibhav Hiremath arche_pdata->num_apbs = of_get_child_count(np); 3147fa60654SVaibhav Hiremath dev_dbg(dev, "Number of APB's available - %d\n", arche_pdata->num_apbs); 3157fa60654SVaibhav Hiremath 316a463fc15SVaibhav Hiremath arche_pdata->wake_detect_gpio = of_get_named_gpio(np, "svc,wake-detect-gpio", 0); 317a463fc15SVaibhav Hiremath if (arche_pdata->wake_detect_gpio < 0) { 318a463fc15SVaibhav Hiremath dev_err(dev, "failed to get wake detect gpio\n"); 319a463fc15SVaibhav Hiremath ret = arche_pdata->wake_detect_gpio; 320758ca99dSVaibhav Hiremath return ret; 32172a8c24bSViresh Kumar } 3227fa60654SVaibhav Hiremath 323a463fc15SVaibhav Hiremath ret = devm_gpio_request(dev, arche_pdata->wake_detect_gpio, "wake detect"); 324a463fc15SVaibhav Hiremath if (ret) { 325a463fc15SVaibhav Hiremath dev_err(dev, "Failed requesting wake_detect gpio %d\n", 326a463fc15SVaibhav Hiremath arche_pdata->wake_detect_gpio); 327758ca99dSVaibhav Hiremath return ret; 328a463fc15SVaibhav Hiremath } 329057aad29SMichael Scott /* deassert wake detect */ 330057aad29SMichael Scott gpio_direction_output(arche_pdata->wake_detect_gpio, 0); 331a463fc15SVaibhav Hiremath 332a463fc15SVaibhav Hiremath arche_pdata->dev = &pdev->dev; 333a463fc15SVaibhav Hiremath 3342923c58eSVaibhav Hiremath ret = device_create_file(dev, &dev_attr_state); 3352923c58eSVaibhav Hiremath if (ret) { 3362923c58eSVaibhav Hiremath dev_err(dev, "failed to create state file in sysfs\n"); 3372923c58eSVaibhav Hiremath return ret; 3382923c58eSVaibhav Hiremath } 3392923c58eSVaibhav Hiremath 340758ca99dSVaibhav Hiremath ret = arche_platform_coldboot_seq(arche_pdata); 341758ca99dSVaibhav Hiremath if (ret) { 342758ca99dSVaibhav Hiremath dev_err(dev, "Failed to cold boot svc %d\n", ret); 3436743a6fdSVaibhav Hiremath goto err_coldboot; 344758ca99dSVaibhav Hiremath } 345758ca99dSVaibhav Hiremath 346fd60ac58SVaibhav Hiremath ret = of_platform_populate(np, NULL, NULL, dev); 347fd60ac58SVaibhav Hiremath if (ret) { 348fd60ac58SVaibhav Hiremath dev_err(dev, "failed to populate child nodes %d\n", ret); 3496743a6fdSVaibhav Hiremath goto err_populate; 350fd60ac58SVaibhav Hiremath } 351fd60ac58SVaibhav Hiremath 352db5a3bcaSVaibhav Hiremath INIT_DELAYED_WORK(&arche_pdata->delayed_work, hub_conf_delayed_work); 353fd60ac58SVaibhav Hiremath 3547fa60654SVaibhav Hiremath dev_info(dev, "Device registered successfully\n"); 35572a8c24bSViresh Kumar return 0; 3566743a6fdSVaibhav Hiremath 3576743a6fdSVaibhav Hiremath err_populate: 3586743a6fdSVaibhav Hiremath arche_platform_poweroff_seq(arche_pdata); 3596743a6fdSVaibhav Hiremath err_coldboot: 3606743a6fdSVaibhav Hiremath device_remove_file(&pdev->dev, &dev_attr_state); 3616743a6fdSVaibhav Hiremath return ret; 3627fa60654SVaibhav Hiremath } 3637fa60654SVaibhav Hiremath 364bc142bbbSVaibhav Hiremath static int arche_remove_child(struct device *dev, void *unused) 365bc142bbbSVaibhav Hiremath { 366bc142bbbSVaibhav Hiremath struct platform_device *pdev = to_platform_device(dev); 367bc142bbbSVaibhav Hiremath 368bc142bbbSVaibhav Hiremath platform_device_unregister(pdev); 369bc142bbbSVaibhav Hiremath 370bc142bbbSVaibhav Hiremath return 0; 371bc142bbbSVaibhav Hiremath } 372bc142bbbSVaibhav Hiremath 3737fa60654SVaibhav Hiremath static int arche_platform_remove(struct platform_device *pdev) 3747fa60654SVaibhav Hiremath { 3757fa60654SVaibhav Hiremath struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev); 3767fa60654SVaibhav Hiremath 3772923c58eSVaibhav Hiremath device_remove_file(&pdev->dev, &dev_attr_state); 37849e6e04bSVaibhav Hiremath cancel_delayed_work_sync(&arche_pdata->delayed_work); 379bc142bbbSVaibhav Hiremath device_for_each_child(&pdev->dev, NULL, arche_remove_child); 3805993e2bfSVaibhav Hiremath arche_platform_poweroff_seq(arche_pdata); 3817fa60654SVaibhav Hiremath platform_set_drvdata(pdev, NULL); 3827fa60654SVaibhav Hiremath 383ad4d3f95SVaibhav Hiremath if (usb3613_hub_mode_ctrl(false)) 384ad4d3f95SVaibhav Hiremath dev_warn(arche_pdata->dev, "failed to control hub device\n"); 385ad4d3f95SVaibhav Hiremath /* TODO: Should we do anything more here ?? */ 3867fa60654SVaibhav Hiremath return 0; 3877fa60654SVaibhav Hiremath } 3887fa60654SVaibhav Hiremath 3897fa60654SVaibhav Hiremath static int arche_platform_suspend(struct device *dev) 3907fa60654SVaibhav Hiremath { 3917fa60654SVaibhav Hiremath /* 3927fa60654SVaibhav Hiremath * If timing profile premits, we may shutdown bridge 3937fa60654SVaibhav Hiremath * completely 3947fa60654SVaibhav Hiremath * 3957fa60654SVaibhav Hiremath * TODO: sequence ?? 3967fa60654SVaibhav Hiremath * 3977fa60654SVaibhav Hiremath * Also, need to make sure we meet precondition for unipro suspend 3987fa60654SVaibhav Hiremath * Precondition: Definition ??? 3997fa60654SVaibhav Hiremath */ 4007fa60654SVaibhav Hiremath return 0; 4017fa60654SVaibhav Hiremath } 4027fa60654SVaibhav Hiremath 4037fa60654SVaibhav Hiremath static int arche_platform_resume(struct device *dev) 4047fa60654SVaibhav Hiremath { 4057fa60654SVaibhav Hiremath /* 4067fa60654SVaibhav Hiremath * Atleast for ES2 we have to meet the delay requirement between 4077fa60654SVaibhav Hiremath * unipro switch and AP bridge init, depending on whether bridge is in 4087fa60654SVaibhav Hiremath * OFF state or standby state. 4097fa60654SVaibhav Hiremath * 4107fa60654SVaibhav Hiremath * Based on whether bridge is in standby or OFF state we may have to 4117fa60654SVaibhav Hiremath * assert multiple signals. Please refer to WDM spec, for more info. 4127fa60654SVaibhav Hiremath * 4137fa60654SVaibhav Hiremath */ 4147fa60654SVaibhav Hiremath return 0; 4157fa60654SVaibhav Hiremath } 4167fa60654SVaibhav Hiremath 4177fa60654SVaibhav Hiremath static SIMPLE_DEV_PM_OPS(arche_platform_pm_ops, 4187fa60654SVaibhav Hiremath arche_platform_suspend, 4197fa60654SVaibhav Hiremath arche_platform_resume); 4207fa60654SVaibhav Hiremath 4217fa60654SVaibhav Hiremath static struct of_device_id arche_platform_of_match[] = { 4227fa60654SVaibhav Hiremath { .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */ 4237fa60654SVaibhav Hiremath { }, 4247fa60654SVaibhav Hiremath }; 4251e5dd1f8SGreg Kroah-Hartman 4261e5dd1f8SGreg Kroah-Hartman static struct of_device_id arche_apb_ctrl_of_match[] = { 4271e5dd1f8SGreg Kroah-Hartman { .compatible = "usbffff,2", }, 4281e5dd1f8SGreg Kroah-Hartman { }, 4291e5dd1f8SGreg Kroah-Hartman }; 4301e5dd1f8SGreg Kroah-Hartman 4311e5dd1f8SGreg Kroah-Hartman static struct of_device_id arche_combined_id[] = { 4321e5dd1f8SGreg Kroah-Hartman { .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */ 4331e5dd1f8SGreg Kroah-Hartman { .compatible = "usbffff,2", }, 4341e5dd1f8SGreg Kroah-Hartman { }, 4351e5dd1f8SGreg Kroah-Hartman }; 4361e5dd1f8SGreg Kroah-Hartman MODULE_DEVICE_TABLE(of, arche_combined_id); 4377fa60654SVaibhav Hiremath 4387fa60654SVaibhav Hiremath static struct platform_driver arche_platform_device_driver = { 4397fa60654SVaibhav Hiremath .probe = arche_platform_probe, 4407fa60654SVaibhav Hiremath .remove = arche_platform_remove, 4417fa60654SVaibhav Hiremath .driver = { 4427fa60654SVaibhav Hiremath .name = "arche-platform-ctrl", 4437fa60654SVaibhav Hiremath .pm = &arche_platform_pm_ops, 4441e5dd1f8SGreg Kroah-Hartman .of_match_table = arche_platform_of_match, 4457fa60654SVaibhav Hiremath } 4467fa60654SVaibhav Hiremath }; 4477fa60654SVaibhav Hiremath 4481e5dd1f8SGreg Kroah-Hartman static struct platform_driver arche_apb_ctrl_device_driver = { 4491e5dd1f8SGreg Kroah-Hartman .probe = arche_apb_ctrl_probe, 4501e5dd1f8SGreg Kroah-Hartman .remove = arche_apb_ctrl_remove, 4511e5dd1f8SGreg Kroah-Hartman .driver = { 4521e5dd1f8SGreg Kroah-Hartman .name = "arche-apb-ctrl", 4531e5dd1f8SGreg Kroah-Hartman .pm = &arche_apb_ctrl_pm_ops, 4541e5dd1f8SGreg Kroah-Hartman .of_match_table = arche_apb_ctrl_of_match, 4551e5dd1f8SGreg Kroah-Hartman } 4561e5dd1f8SGreg Kroah-Hartman }; 4571e5dd1f8SGreg Kroah-Hartman 4581e5dd1f8SGreg Kroah-Hartman static int __init arche_init(void) 4591e5dd1f8SGreg Kroah-Hartman { 4601e5dd1f8SGreg Kroah-Hartman int retval; 4611e5dd1f8SGreg Kroah-Hartman 4621e5dd1f8SGreg Kroah-Hartman retval = platform_driver_register(&arche_platform_device_driver); 4631e5dd1f8SGreg Kroah-Hartman if (retval) 4641e5dd1f8SGreg Kroah-Hartman return retval; 4651e5dd1f8SGreg Kroah-Hartman 4661e5dd1f8SGreg Kroah-Hartman retval = platform_driver_register(&arche_apb_ctrl_device_driver); 4671e5dd1f8SGreg Kroah-Hartman if (retval) 4681e5dd1f8SGreg Kroah-Hartman platform_driver_unregister(&arche_platform_device_driver); 4691e5dd1f8SGreg Kroah-Hartman 4701e5dd1f8SGreg Kroah-Hartman return retval; 4711e5dd1f8SGreg Kroah-Hartman } 4721e5dd1f8SGreg Kroah-Hartman module_init(arche_init); 4731e5dd1f8SGreg Kroah-Hartman 4741e5dd1f8SGreg Kroah-Hartman static void __exit arche_exit(void) 4751e5dd1f8SGreg Kroah-Hartman { 4761e5dd1f8SGreg Kroah-Hartman platform_driver_unregister(&arche_apb_ctrl_device_driver); 4771e5dd1f8SGreg Kroah-Hartman platform_driver_unregister(&arche_platform_device_driver); 4781e5dd1f8SGreg Kroah-Hartman } 4791e5dd1f8SGreg Kroah-Hartman module_exit(arche_exit); 4807fa60654SVaibhav Hiremath 4817fa60654SVaibhav Hiremath MODULE_LICENSE("GPL"); 4827fa60654SVaibhav Hiremath MODULE_AUTHOR("Vaibhav Hiremath <vaibhav.hiremath@linaro.org>"); 4837fa60654SVaibhav Hiremath MODULE_DESCRIPTION("Arche Platform Driver"); 484