Release 4.11 drivers/staging/greybus/arche-platform.c
/*
* Arche Platform driver to enable Unipro link.
*
* Copyright 2014-2015 Google Inc.
* Copyright 2014-2015 Linaro Ltd.
*
* Released under the GPLv2 only.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/suspend.h>
#include <linux/time.h>
#include "arche_platform.h"
#include "greybus.h"
#include <linux/usb/usb3613.h>
#define WD_COLDBOOT_PULSE_WIDTH_MS 30
enum svc_wakedetect_state {
WD_STATE_IDLE, /* Default state = pulled high/low */
WD_STATE_BOOT_INIT, /* WD = falling edge (low) */
WD_STATE_COLDBOOT_TRIG, /* WD = rising edge (high), > 30msec */
WD_STATE_STANDBYBOOT_TRIG, /* As of now not used ?? */
WD_STATE_COLDBOOT_START, /* Cold boot process started */
WD_STATE_STANDBYBOOT_START, /* Not used */
WD_STATE_TIMESYNC,
};
struct arche_platform_drvdata {
/* Control GPIO signals to and from AP <=> SVC */
int svc_reset_gpio;
bool is_reset_act_hi;
int svc_sysboot_gpio;
int wake_detect_gpio; /* bi-dir,maps to WAKE_MOD & WAKE_FRAME signals */
enum arche_platform_state state;
int svc_refclk_req;
struct clk *svc_ref_clk;
struct pinctrl *pinctrl;
struct pinctrl_state *pin_default;
int num_apbs;
enum svc_wakedetect_state wake_detect_state;
int wake_detect_irq;
spinlock_t wake_lock; /* Protect wake_detect_state */
struct mutex platform_state_mutex; /* Protect state */
wait_queue_head_t wq; /* WQ for arche_pdata->state */
unsigned long wake_detect_start;
struct notifier_block pm_notifier;
struct device *dev;
struct gb_timesync_svc *timesync_svc_pdata;
};
static int arche_apb_bootret_assert(struct device *dev, void *data)
{
apb_bootret_assert(dev);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Bryan O'Donoghue | 23 | 100.00% | 1 | 100.00% |
Total | 23 | 100.00% | 1 | 100.00% |
static int arche_apb_bootret_deassert(struct device *dev, void *data)
{
apb_bootret_deassert(dev);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Bryan O'Donoghue | 23 | 100.00% | 1 | 100.00% |
Total | 23 | 100.00% | 1 | 100.00% |
/* Requires calling context to hold arche_pdata->platform_state_mutex */
static void arche_platform_set_state(struct arche_platform_drvdata *arche_pdata,
enum arche_platform_state state)
{
arche_pdata->state = state;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Bryan O'Donoghue | 21 | 100.00% | 1 | 100.00% |
Total | 21 | 100.00% | 1 | 100.00% |
/*
* arche_platform_change_state: Change the operational state
*
* This exported function allows external drivers to change the state
* of the arche-platform driver.
* Note that this function only supports transitions between two states
* with limited functionality.
*
* - ARCHE_PLATFORM_STATE_TIME_SYNC:
* Once set, allows timesync operations between SVC <=> AP and makes
* sure that arche-platform driver ignores any subsequent events/pulses
* from SVC over wake/detect.
*
* - ARCHE_PLATFORM_STATE_ACTIVE:
* Puts back driver to active state, where any pulse from SVC on wake/detect
* line would trigger either cold/standby boot.
* Note: Transition request from this function does not trigger cold/standby
* boot. It just puts back driver book keeping variable back to ACTIVE
* state and restores the interrupt.
*
* Returns -ENODEV if device not found, -EAGAIN if the driver cannot currently
* satisfy the requested state-transition or -EINVAL for all other
* state-transition requests.
*/
int arche_platform_change_state(enum arche_platform_state state,
struct gb_timesync_svc *timesync_svc_pdata)
{
struct arche_platform_drvdata *arche_pdata;
struct platform_device *pdev;
struct device_node *np;
int ret = -EAGAIN;
unsigned long flags;
np = of_find_compatible_node(NULL, NULL, "google,arche-platform");
if (!np) {
pr_err("google,arche-platform device node not found\n");
return -ENODEV;
}
pdev = of_find_device_by_node(np);
if (!pdev) {
pr_err("arche-platform device not found\n");
of_node_put(np);
return -ENODEV;
}
arche_pdata = platform_get_drvdata(pdev);
mutex_lock(&arche_pdata->platform_state_mutex);
spin_lock_irqsave(&arche_pdata->wake_lock, flags);
if (arche_pdata->state == state) {
ret = 0;
goto exit;
}
switch (state) {
case ARCHE_PLATFORM_STATE_TIME_SYNC:
if (arche_pdata->state != ARCHE_PLATFORM_STATE_ACTIVE) {
ret = -EINVAL;
goto exit;
}
if (arche_pdata->wake_detect_state != WD_STATE_IDLE) {
dev_err(arche_pdata->dev,
"driver busy with wake/detect line ops\n");
goto exit;
}
device_for_each_child(arche_pdata->dev, NULL,
arche_apb_bootret_assert);
arche_pdata->wake_detect_state = WD_STATE_TIMESYNC;
break;
case ARCHE_PLATFORM_STATE_ACTIVE:
if (arche_pdata->state != ARCHE_PLATFORM_STATE_TIME_SYNC) {
ret = -EINVAL;
goto exit;
}
device_for_each_child(arche_pdata->dev, NULL,
arche_apb_bootret_deassert);
arche_pdata->wake_detect_state = WD_STATE_IDLE;
break;
case ARCHE_PLATFORM_STATE_OFF:
case ARCHE_PLATFORM_STATE_STANDBY:
case ARCHE_PLATFORM_STATE_FW_FLASHING:
dev_err(arche_pdata->dev, "busy, request to retry later\n");
goto exit;
default:
ret = -EINVAL;
dev_err(arche_pdata->dev,
"invalid state transition request\n");
goto exit;
}
arche_pdata->timesync_svc_pdata = timesync_svc_pdata;
arche_platform_set_state(arche_pdata, state);
if (state == ARCHE_PLATFORM_STATE_ACTIVE)
wake_up(&arche_pdata->wq);
ret = 0;
exit:
spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
mutex_unlock(&arche_pdata->platform_state_mutex);
put_device(&pdev->dev);
of_node_put(np);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 203 | 58.33% | 1 | 20.00% |
Bryan O'Donoghue | 132 | 37.93% | 2 | 40.00% |
Johan Hovold | 8 | 2.30% | 1 | 20.00% |
Wei Yongjun | 5 | 1.44% | 1 | 20.00% |
Total | 348 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL_GPL(arche_platform_change_state);
/* Requires arche_pdata->wake_lock is held by calling context */
static void arche_platform_set_wake_detect_state(
struct arche_platform_drvdata *arche_pdata,
enum svc_wakedetect_state state)
{
arche_pdata->wake_detect_state = state;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Bryan O'Donoghue | 21 | 100.00% | 1 | 100.00% |
Total | 21 | 100.00% | 1 | 100.00% |
static inline void svc_reset_onoff(unsigned int gpio, bool onoff)
{
gpio_set_value(gpio, onoff);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 21 | 100.00% | 2 | 100.00% |
Total | 21 | 100.00% | 2 | 100.00% |
static int apb_cold_boot(struct device *dev, void *data)
{
int ret;
ret = apb_ctrl_coldboot(dev);
if (ret)
dev_warn(dev, "failed to coldboot\n");
/*Child nodes are independent, so do not exit coldboot operation */
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 40 | 100.00% | 1 | 100.00% |
Total | 40 | 100.00% | 1 | 100.00% |
static int apb_poweroff(struct device *dev, void *data)
{
apb_ctrl_poweroff(dev);
/* Enable HUB3613 into HUB mode. */
if (usb3613_hub_mode_ctrl(false))
dev_warn(dev, "failed to control hub device\n");
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 38 | 100.00% | 2 | 100.00% |
Total | 38 | 100.00% | 2 | 100.00% |
static void arche_platform_wd_irq_en(struct arche_platform_drvdata *arche_pdata)
{
/* Enable interrupt here, to read event back from SVC */
gpio_direction_input(arche_pdata->wake_detect_gpio);
enable_irq(arche_pdata->wake_detect_irq);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 26 | 100.00% | 2 | 100.00% |
Total | 26 | 100.00% | 2 | 100.00% |
static irqreturn_t arche_platform_wd_irq_thread(int irq, void *devid)
{
struct arche_platform_drvdata *arche_pdata = devid;
unsigned long flags;
spin_lock_irqsave(&arche_pdata->wake_lock, flags);
if (arche_pdata->wake_detect_state != WD_STATE_COLDBOOT_TRIG) {
/* Something is wrong */
spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
return IRQ_HANDLED;
}
arche_platform_set_wake_detect_state(arche_pdata,
WD_STATE_COLDBOOT_START);
spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
/* It should complete power cycle, so first make sure it is poweroff */
device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
/* Bring APB out of reset: cold boot sequence */
device_for_each_child(arche_pdata->dev, NULL, apb_cold_boot);
/* Enable HUB3613 into HUB mode. */
if (usb3613_hub_mode_ctrl(true))
dev_warn(arche_pdata->dev, "failed to control hub device\n");
spin_lock_irqsave(&arche_pdata->wake_lock, flags);
arche_platform_set_wake_detect_state(arche_pdata, WD_STATE_IDLE);
spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
return IRQ_HANDLED;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 138 | 94.52% | 4 | 80.00% |
Bryan O'Donoghue | 8 | 5.48% | 1 | 20.00% |
Total | 146 | 100.00% | 5 | 100.00% |
static irqreturn_t arche_platform_wd_irq(int irq, void *devid)
{
struct arche_platform_drvdata *arche_pdata = devid;
unsigned long flags;
spin_lock_irqsave(&arche_pdata->wake_lock, flags);
if (arche_pdata->wake_detect_state == WD_STATE_TIMESYNC) {
gb_timesync_irq(arche_pdata->timesync_svc_pdata);
goto exit;
}
if (gpio_get_value(arche_pdata->wake_detect_gpio)) {
/* wake/detect rising */
/*
* If wake/detect line goes high after low, within less than
* 30msec, then standby boot sequence is initiated, which is not
* supported/implemented as of now. So ignore it.
*/
if (arche_pdata->wake_detect_state == WD_STATE_BOOT_INIT) {
if (time_before(jiffies,
arche_pdata->wake_detect_start +
msecs_to_jiffies(WD_COLDBOOT_PULSE_WIDTH_MS))) {
arche_platform_set_wake_detect_state(arche_pdata,
WD_STATE_IDLE);
} else {
/* Check we are not in middle of irq thread already */
if (arche_pdata->wake_detect_state !=
WD_STATE_COLDBOOT_START) {
arche_platform_set_wake_detect_state(arche_pdata,
WD_STATE_COLDBOOT_TRIG);
spin_unlock_irqrestore(
&arche_pdata->wake_lock,
flags);
return IRQ_WAKE_THREAD;
}
}
}
} else {
/* wake/detect falling */
if (arche_pdata->wake_detect_state == WD_STATE_IDLE) {
arche_pdata->wake_detect_start = jiffies;
/*
* In the begining, when wake/detect goes low
* (first time), we assume it is meant for coldboot
* and set the flag. If wake/detect line stays low
* beyond 30msec, then it is coldboot else fallback
* to standby boot.
*/
arche_platform_set_wake_detect_state(arche_pdata,
WD_STATE_BOOT_INIT);
}
}
exit:
spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
return IRQ_HANDLED;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 144 | 80.45% | 2 | 40.00% |
Bryan O'Donoghue | 34 | 18.99% | 2 | 40.00% |
Gioh Kim | 1 | 0.56% | 1 | 20.00% |
Total | 179 | 100.00% | 5 | 100.00% |
/*
* Requires arche_pdata->platform_state_mutex to be held
*/
static int
arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdata)
{
int ret;
if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE)
return 0;
dev_info(arche_pdata->dev, "Booting from cold boot state\n");
svc_reset_onoff(arche_pdata->svc_reset_gpio,
arche_pdata->is_reset_act_hi);
gpio_set_value(arche_pdata->svc_sysboot_gpio, 0);
usleep_range(100, 200);
ret = clk_prepare_enable(arche_pdata->svc_ref_clk);
if (ret) {
dev_err(arche_pdata->dev, "failed to enable svc_ref_clk: %d\n",
ret);
return ret;
}
/* bring SVC out of reset */
svc_reset_onoff(arche_pdata->svc_reset_gpio,
!arche_pdata->is_reset_act_hi);
arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_ACTIVE);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 109 | 96.46% | 3 | 75.00% |
Bryan O'Donoghue | 4 | 3.54% | 1 | 25.00% |
Total | 113 | 100.00% | 4 | 100.00% |
/*
* Requires arche_pdata->platform_state_mutex to be held
*/
static int
arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_pdata)
{
int ret;
if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
return 0;
dev_info(arche_pdata->dev, "Switching to FW flashing state\n");
svc_reset_onoff(arche_pdata->svc_reset_gpio,
arche_pdata->is_reset_act_hi);
gpio_set_value(arche_pdata->svc_sysboot_gpio, 1);
usleep_range(100, 200);
ret = clk_prepare_enable(arche_pdata->svc_ref_clk);
if (ret) {
dev_err(arche_pdata->dev, "failed to enable svc_ref_clk: %d\n",
ret);
return ret;
}
svc_reset_onoff(arche_pdata->svc_reset_gpio,
!arche_pdata->is_reset_act_hi);
arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_FW_FLASHING);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 108 | 96.43% | 4 | 80.00% |
Bryan O'Donoghue | 4 | 3.57% | 1 | 20.00% |
Total | 112 | 100.00% | 5 | 100.00% |
/*
* Requires arche_pdata->platform_state_mutex to be held
*/
static void
arche_platform_poweroff_seq(struct arche_platform_drvdata *arche_pdata)
{
unsigned long flags;
if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF)
return;
/* If in fw_flashing mode, then no need to repeate things again */
if (arche_pdata->state != ARCHE_PLATFORM_STATE_FW_FLASHING) {
disable_irq(arche_pdata->wake_detect_irq);
spin_lock_irqsave(&arche_pdata->wake_lock, flags);
arche_platform_set_wake_detect_state(arche_pdata,
WD_STATE_IDLE);
spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
}
clk_disable_unprepare(arche_pdata->svc_ref_clk);
/* As part of exit, put APB back in reset state */
svc_reset_onoff(arche_pdata->svc_reset_gpio,
arche_pdata->is_reset_act_hi);
arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 87 | 91.58% | 13 | 92.86% |
Bryan O'Donoghue | 8 | 8.42% | 1 | 7.14% |
Total | 95 | 100.00% | 14 | 100.00% |
static ssize_t state_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct platform_device *pdev = to_platform_device(dev);
struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
int ret = 0;
retry:
mutex_lock(&arche_pdata->platform_state_mutex);
if (arche_pdata->state == ARCHE_PLATFORM_STATE_TIME_SYNC) {
mutex_unlock(&arche_pdata->platform_state_mutex);
ret = wait_event_interruptible(
arche_pdata->wq,
arche_pdata->state != ARCHE_PLATFORM_STATE_TIME_SYNC);
if (ret)
return ret;
goto retry;
}
if (sysfs_streq(buf, "off")) {
if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF)
goto exit;
/* If SVC goes down, bring down APB's as well */
device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
arche_platform_poweroff_seq(arche_pdata);
} else if (sysfs_streq(buf, "active")) {
if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE)
goto exit;
/* First we want to make sure we power off everything
* and then activate back again
*/
device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
arche_platform_poweroff_seq(arche_pdata);
arche_platform_wd_irq_en(arche_pdata);
ret = arche_platform_coldboot_seq(arche_pdata);
if (ret)
goto exit;
} else if (sysfs_streq(buf, "standby")) {
if (arche_pdata->state == ARCHE_PLATFORM_STATE_STANDBY)
goto exit;
dev_warn(arche_pdata->dev, "standby state not supported\n");
} else if (sysfs_streq(buf, "fw_flashing")) {
if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
goto exit;
/*
* Here we only control SVC.
*
* In case of FW_FLASHING mode we do not want to control
* APBs, as in case of V2, SPI bus is shared between both
* the APBs. So let user chose which APB he wants to flash.
*/
arche_platform_poweroff_seq(arche_pdata);
ret = arche_platform_fw_flashing_seq(arche_pdata);
if (ret)
goto exit;
} else {
dev_err(arche_pdata->dev, "unknown state\n");
ret = -EINVAL;
}
exit:
mutex_unlock(&arche_pdata->platform_state_mutex);
return ret ? ret : count;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 263 | 85.11% | 10 | 83.33% |
Bryan O'Donoghue | 45 | 14.56% | 1 | 8.33% |
Elise Lennion | 1 | 0.32% | 1 | 8.33% |
Total | 309 | 100.00% | 12 | 100.00% |
static ssize_t state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct arche_platform_drvdata *arche_pdata = dev_get_drvdata(dev);
switch (arche_pdata->state) {
case ARCHE_PLATFORM_STATE_OFF:
return sprintf(buf, "off\n");
case ARCHE_PLATFORM_STATE_ACTIVE:
return sprintf(buf, "active\n");
case ARCHE_PLATFORM_STATE_STANDBY:
return sprintf(buf, "standby\n");
case ARCHE_PLATFORM_STATE_FW_FLASHING:
return sprintf(buf, "fw_flashing\n");
case ARCHE_PLATFORM_STATE_TIME_SYNC:
return sprintf(buf, "time_sync\n");
default:
return sprintf(buf, "unknown state\n");
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 102 | 100.00% | 3 | 100.00% |
Total | 102 | 100.00% | 3 | 100.00% |
static DEVICE_ATTR_RW(state);
static int arche_platform_pm_notifier(struct notifier_block *notifier,
unsigned long pm_event, void *unused)
{
struct arche_platform_drvdata *arche_pdata =
container_of(notifier, struct arche_platform_drvdata,
pm_notifier);
int ret = NOTIFY_DONE;
mutex_lock(&arche_pdata->platform_state_mutex);
switch (pm_event) {
case PM_SUSPEND_PREPARE:
if (arche_pdata->state != ARCHE_PLATFORM_STATE_ACTIVE) {
ret = NOTIFY_STOP;
break;
}
device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
arche_platform_poweroff_seq(arche_pdata);
break;
case PM_POST_SUSPEND:
if (arche_pdata->state != ARCHE_PLATFORM_STATE_OFF)
break;
arche_platform_wd_irq_en(arche_pdata);
arche_platform_coldboot_seq(arche_pdata);
break;
default:
break;
}
mutex_unlock(&arche_pdata->platform_state_mutex);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David Lin | 85 | 68.55% | 1 | 20.00% |
Vaibhav Hiremath | 39 | 31.45% | 4 | 80.00% |
Total | 124 | 100.00% | 5 | 100.00% |
static int arche_platform_probe(struct platform_device *pdev)
{
struct arche_platform_drvdata *arche_pdata;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
int ret;
arche_pdata = devm_kzalloc(&pdev->dev, sizeof(*arche_pdata),
GFP_KERNEL);
if (!arche_pdata)
return -ENOMEM;
/* setup svc reset gpio */
arche_pdata->is_reset_act_hi = of_property_read_bool(np,
"svc,reset-active-high");
arche_pdata->svc_reset_gpio = of_get_named_gpio(np,
"svc,reset-gpio",
0);
if (arche_pdata->svc_reset_gpio < 0) {
dev_err(dev, "failed to get reset-gpio\n");
return arche_pdata->svc_reset_gpio;
}
ret = devm_gpio_request(dev, arche_pdata->svc_reset_gpio, "svc-reset");
if (ret) {
dev_err(dev, "failed to request svc-reset gpio:%d\n", ret);
return ret;
}
ret = gpio_direction_output(arche_pdata->svc_reset_gpio,
arche_pdata->is_reset_act_hi);
if (ret) {
dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
return ret;
}
arche_platform_set_state(arche_pdata, ARCHE_PLATFORM_STATE_OFF);
arche_pdata->svc_sysboot_gpio = of_get_named_gpio(np,
"svc,sysboot-gpio", 0);
if (arche_pdata->svc_sysboot_gpio < 0) {
dev_err(dev, "failed to get sysboot gpio\n");
return arche_pdata->svc_sysboot_gpio;
}
ret = devm_gpio_request(dev, arche_pdata->svc_sysboot_gpio, "sysboot0");
if (ret) {
dev_err(dev, "failed to request sysboot0 gpio:%d\n", ret);
return ret;
}
ret = gpio_direction_output(arche_pdata->svc_sysboot_gpio, 0);
if (ret) {
dev_err(dev, "failed to set svc-reset gpio dir:%d\n", ret);
return ret;
}
/* setup the clock request gpio first */
arche_pdata->svc_refclk_req = of_get_named_gpio(np,
"svc,refclk-req-gpio", 0);
if (arche_pdata->svc_refclk_req < 0) {
dev_err(dev, "failed to get svc clock-req gpio\n");
return arche_pdata->svc_refclk_req;
}
ret = devm_gpio_request(dev, arche_pdata->svc_refclk_req,
"svc-clk-req");
if (ret) {
dev_err(dev, "failed to request svc-clk-req gpio: %d\n", ret);
return ret;
}
ret = gpio_direction_input(arche_pdata->svc_refclk_req);
if (ret) {
dev_err(dev, "failed to set svc-clk-req gpio dir :%d\n", ret);
return ret;
}
/* setup refclk2 to follow the pin */
arche_pdata->svc_ref_clk = devm_clk_get(dev, "svc_ref_clk");
if (IS_ERR(arche_pdata->svc_ref_clk)) {
ret = PTR_ERR(arche_pdata->svc_ref_clk);
dev_err(dev, "failed to get svc_ref_clk: %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, arche_pdata);
arche_pdata->num_apbs = of_get_child_count(np);
dev_dbg(dev, "Number of APB's available - %d\n", arche_pdata->num_apbs);
arche_pdata->wake_detect_gpio = of_get_named_gpio(np,
"svc,wake-detect-gpio",
0);
if (arche_pdata->wake_detect_gpio < 0) {
dev_err(dev, "failed to get wake detect gpio\n");
return arche_pdata->wake_detect_gpio;
}
ret = devm_gpio_request(dev, arche_pdata->wake_detect_gpio,
"wake detect");
if (ret) {
dev_err(dev, "Failed requesting wake_detect gpio %d\n",
arche_pdata->wake_detect_gpio);
return ret;
}
arche_platform_set_wake_detect_state(arche_pdata, WD_STATE_IDLE);
arche_pdata->dev = &pdev->dev;
spin_lock_init(&arche_pdata->wake_lock);
mutex_init(&arche_pdata->platform_state_mutex);
init_waitqueue_head(&arche_pdata->wq);
arche_pdata->wake_detect_irq =
gpio_to_irq(arche_pdata->wake_detect_gpio);
ret = devm_request_threaded_irq(dev, arche_pdata->wake_detect_irq,
arche_platform_wd_irq,
arche_platform_wd_irq_thread,
IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(dev), arche_pdata);
if (ret) {
dev_err(dev, "failed to request wake detect IRQ %d\n", ret);
return ret;
}
disable_irq(arche_pdata->wake_detect_irq);
ret = device_create_file(dev, &dev_attr_state);
if (ret) {
dev_err(dev, "failed to create state file in sysfs\n");
return ret;
}
ret = of_platform_populate(np, NULL, NULL, dev);
if (ret) {
dev_err(dev, "failed to populate child nodes %d\n", ret);
goto err_device_remove;
}
arche_pdata->pm_notifier.notifier_call = arche_platform_pm_notifier;
ret = register_pm_notifier(&arche_pdata->pm_notifier);
if (ret) {
dev_err(dev, "failed to register pm notifier %d\n", ret);
goto err_device_remove;
}
/* Register callback pointer */
arche_platform_change_state_cb = arche_platform_change_state;
/* Explicitly power off if requested */
if (!of_property_read_bool(pdev->dev.of_node, "arche,init-off")) {
mutex_lock(&arche_pdata->platform_state_mutex);
ret = arche_platform_coldboot_seq(arche_pdata);
if (ret) {
dev_err(dev, "Failed to cold boot svc %d\n", ret);
goto err_coldboot;
}
arche_platform_wd_irq_en(arche_pdata);
mutex_unlock(&arche_pdata->platform_state_mutex);
}
dev_info(dev, "Device registered successfully\n");
return 0;
err_coldboot:
mutex_unlock(&arche_pdata->platform_state_mutex);
err_device_remove:
device_remove_file(&pdev->dev, &dev_attr_state);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 742 | 91.60% | 14 | 66.67% |
David Lin | 34 | 4.20% | 1 | 4.76% |
Bryan O'Donoghue | 18 | 2.22% | 3 | 14.29% |
Viresh Kumar | 15 | 1.85% | 2 | 9.52% |
Eva Rachel Retuya | 1 | 0.12% | 1 | 4.76% |
Total | 810 | 100.00% | 21 | 100.00% |
static int arche_remove_child(struct device *dev, void *unused)
{
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 33 | 100.00% | 1 | 100.00% |
Total | 33 | 100.00% | 1 | 100.00% |
static int arche_platform_remove(struct platform_device *pdev)
{
struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
unregister_pm_notifier(&arche_pdata->pm_notifier);
device_remove_file(&pdev->dev, &dev_attr_state);
device_for_each_child(&pdev->dev, NULL, arche_remove_child);
arche_platform_poweroff_seq(arche_pdata);
platform_set_drvdata(pdev, NULL);
if (usb3613_hub_mode_ctrl(false))
dev_warn(arche_pdata->dev, "failed to control hub device\n");
/* TODO: Should we do anything more here ?? */
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 76 | 90.48% | 6 | 85.71% |
David Lin | 8 | 9.52% | 1 | 14.29% |
Total | 84 | 100.00% | 7 | 100.00% |
static int arche_platform_suspend(struct device *dev)
{
/*
* If timing profile premits, we may shutdown bridge
* completely
*
* TODO: sequence ??
*
* Also, need to make sure we meet precondition for unipro suspend
* Precondition: Definition ???
*/
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 15 | 100.00% | 2 | 100.00% |
Total | 15 | 100.00% | 2 | 100.00% |
static int arche_platform_resume(struct device *dev)
{
/*
* Atleast for ES2 we have to meet the delay requirement between
* unipro switch and AP bridge init, depending on whether bridge is in
* OFF state or standby state.
*
* Based on whether bridge is in standby or OFF state we may have to
* assert multiple signals. Please refer to WDM spec, for more info.
*
*/
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 15 | 100.00% | 2 | 100.00% |
Total | 15 | 100.00% | 2 | 100.00% |
static void arche_platform_shutdown(struct platform_device *pdev)
{
struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
arche_platform_poweroff_seq(arche_pdata);
usb3613_hub_mode_ctrl(false);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
David Lin | 31 | 100.00% | 1 | 100.00% |
Total | 31 | 100.00% | 1 | 100.00% |
static SIMPLE_DEV_PM_OPS(arche_platform_pm_ops,
arche_platform_suspend,
arche_platform_resume);
static const struct of_device_id arche_platform_of_match[] = {
{ .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */
{ },
};
static const struct of_device_id arche_combined_id[] = {
{ .compatible = "google,arche-platform", }, /* Use PID/VID of SVC device */
{ .compatible = "usbffff,2", },
{ },
};
MODULE_DEVICE_TABLE(of, arche_combined_id);
static struct platform_driver arche_platform_device_driver = {
.probe = arche_platform_probe,
.remove = arche_platform_remove,
.shutdown = arche_platform_shutdown,
.driver = {
.name = "arche-platform-ctrl",
.pm = &arche_platform_pm_ops,
.of_match_table = arche_platform_of_match,
}
};
static int __init arche_init(void)
{
int retval;
retval = platform_driver_register(&arche_platform_device_driver);
if (retval)
return retval;
retval = arche_apb_init();
if (retval)
platform_driver_unregister(&arche_platform_device_driver);
return retval;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 43 | 95.56% | 1 | 50.00% |
Viresh Kumar | 2 | 4.44% | 1 | 50.00% |
Total | 45 | 100.00% | 2 | 100.00% |
module_init(arche_init);
static void __exit arche_exit(void)
{
arche_apb_exit();
platform_driver_unregister(&arche_platform_device_driver);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 13 | 72.22% | 1 | 25.00% |
Vaibhav Hiremath | 3 | 16.67% | 2 | 50.00% |
Viresh Kumar | 2 | 11.11% | 1 | 25.00% |
Total | 18 | 100.00% | 4 | 100.00% |
module_exit(arche_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Vaibhav Hiremath <vaibhav.hiremath@linaro.org>");
MODULE_DESCRIPTION("Arche Platform Driver");
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vaibhav Hiremath | 2435 | 78.52% | 33 | 66.00% |
Bryan O'Donoghue | 357 | 11.51% | 3 | 6.00% |
David Lin | 170 | 5.48% | 2 | 4.00% |
Greg Kroah-Hartman | 94 | 3.03% | 1 | 2.00% |
Viresh Kumar | 26 | 0.84% | 4 | 8.00% |
Johan Hovold | 8 | 0.26% | 1 | 2.00% |
Wei Yongjun | 5 | 0.16% | 1 | 2.00% |
Eva Rachel Retuya | 3 | 0.10% | 2 | 4.00% |
Elise Lennion | 1 | 0.03% | 1 | 2.00% |
Gioh Kim | 1 | 0.03% | 1 | 2.00% |
Sandeep Patil | 1 | 0.03% | 1 | 2.00% |
Total | 3101 | 100.00% | 50 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.