Skip to content

Commit 886aba5

Browse files
hvaibhavgregkh
authored andcommitted
greybus: arche-platform: Export fn to allow timesync driver to change the state
With the addition of the timesync driver and looking at the hardware interfaces we have, its clear we need to add a new arche-platform state. This patch adds ARCHE_PLATFORM_STATE_TIME_SYNC to the arche-platform driver to facilitate transition to the TIME_SYNC state if-and-only-if the arche-platform driver is in the ACTIVE state. This is mainly needed as wake/detect lines are shared between TIMESYNC operation and basic control functionality of APBs. So during TIMESYNC we want to make sure that the events on wake/detect lines are ignored by the arche-platform APB reset logic. This patch adds one exported function, which can be invoked from timesync driver code, allowing, switching between ARCHE_PLATFORM_STATE_TIME_SYNC <=> ARCHE_PLATFORM_STATE_ACTIVE states. [ [email protected]: Added mutex, massaged commit text ] Reviewed-by: Vaibhav Hiremath <[email protected]> Signed-off-by: Vaibhav Hiremath <[email protected]> Signed-off-by: Bryan O'Donoghue <[email protected]> Suggested-by: Alex Elder <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 6c1ca56 commit 886aba5

File tree

2 files changed

+119
-8
lines changed

2 files changed

+119
-8
lines changed

drivers/staging/greybus/arche-platform.c

Lines changed: 117 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,97 @@ struct arche_platform_drvdata {
5555

5656
enum svc_wakedetect_state wake_detect_state;
5757
int wake_detect_irq;
58-
spinlock_t wake_lock; /* Protect wake_detect_state */
58+
spinlock_t wake_lock; /* Protect wake_detect_state */
59+
struct mutex platform_state_mutex; /* Protect state */
5960
unsigned long wake_detect_start;
6061
struct notifier_block pm_notifier;
6162

6263
struct device *dev;
6364
};
6465

66+
/*
67+
* arche_platform_change_state: Change the operational state
68+
*
69+
* This exported function allows external drivers to change the state
70+
* of the arche-platform driver.
71+
* Note that this function only supports transitions between two states
72+
* with limited functionality.
73+
*
74+
* - ARCHE_PLATFORM_STATE_TIME_SYNC:
75+
* Once set, allows timesync operations between SVC <=> AP and makes
76+
* sure that arche-platform driver ignores any subsequent events/pulses
77+
* from SVC over wake/detect.
78+
*
79+
* - ARCHE_PLATFORM_STATE_ACTIVE:
80+
* Puts back driver to active state, where any pulse from SVC on wake/detect
81+
* line would trigger either cold/standby boot.
82+
* Note: Transition request from this function does not trigger cold/standby
83+
* boot. It just puts back driver book keeping variable back to ACTIVE
84+
* state and restores the interrupt.
85+
*
86+
* Returns -ENODEV if device not found, -EAGAIN if the driver cannot currently
87+
* satisfy the requested state-transition or -EINVAL for all other
88+
* state-transition requests.
89+
*/
90+
int arche_platform_change_state(enum arche_platform_state state)
91+
{
92+
struct arche_platform_drvdata *arche_pdata;
93+
struct platform_device *pdev;
94+
struct device_node *np;
95+
int ret = -EAGAIN;
96+
unsigned long flags;
97+
98+
np = of_find_compatible_node(NULL, NULL, "google,arche-platform");
99+
if (!np) {
100+
pr_err("google,arche-platform device node not found\n");
101+
return -ENODEV;
102+
}
103+
104+
pdev = of_find_device_by_node(np);
105+
if (!pdev) {
106+
pr_err("arche-platform device not found\n");
107+
return -ENODEV;
108+
}
109+
110+
arche_pdata = platform_get_drvdata(pdev);
111+
112+
mutex_lock(&arche_pdata->platform_state_mutex);
113+
spin_lock_irqsave(&arche_pdata->wake_lock, flags);
114+
if (arche_pdata->wake_detect_state != WD_STATE_IDLE) {
115+
dev_err(arche_pdata->dev,
116+
"driver busy with wake/detect line ops\n");
117+
goto exit;
118+
}
119+
120+
if (arche_pdata->state == state) {
121+
ret = 0;
122+
goto exit;
123+
}
124+
125+
if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF ||
126+
arche_pdata->state == ARCHE_PLATFORM_STATE_STANDBY ||
127+
arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING) {
128+
dev_err(arche_pdata->dev, "busy, request to retry later\n");
129+
goto exit;
130+
}
131+
132+
if (state == ARCHE_PLATFORM_STATE_TIME_SYNC) {
133+
disable_irq(arche_pdata->wake_detect_irq);
134+
arche_pdata->state = ARCHE_PLATFORM_STATE_TIME_SYNC;
135+
} else if (state == ARCHE_PLATFORM_STATE_ACTIVE) {
136+
arche_pdata->state = ARCHE_PLATFORM_STATE_ACTIVE;
137+
enable_irq(arche_pdata->wake_detect_irq);
138+
} else {
139+
dev_err(arche_pdata->dev, "invalid state transition request\n");
140+
}
141+
exit:
142+
spin_unlock_irqrestore(&arche_pdata->wake_lock, flags);
143+
mutex_unlock(&arche_pdata->platform_state_mutex);
144+
of_node_put(np);
145+
return ret;
146+
}
147+
EXPORT_SYMBOL_GPL(arche_platform_change_state);
148+
65149
static inline void svc_reset_onoff(unsigned int gpio, bool onoff)
66150
{
67151
gpio_set_value(gpio, onoff);
@@ -195,6 +279,9 @@ static irqreturn_t arche_platform_wd_irq(int irq, void *devid)
195279
return IRQ_HANDLED;
196280
}
197281

282+
/*
283+
* Requires arche_pdata->platform_state_mutex to be held
284+
*/
198285
static int arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdata)
199286
{
200287
int ret;
@@ -226,6 +313,9 @@ static int arche_platform_coldboot_seq(struct arche_platform_drvdata *arche_pdat
226313
return 0;
227314
}
228315

316+
/*
317+
* Requires arche_pdata->platform_state_mutex to be held
318+
*/
229319
static void arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_pdata)
230320
{
231321
if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
@@ -246,6 +336,9 @@ static void arche_platform_fw_flashing_seq(struct arche_platform_drvdata *arche_
246336

247337
}
248338

339+
/*
340+
* Requires arche_pdata->platform_state_mutex to be held
341+
*/
249342
static void arche_platform_poweroff_seq(struct arche_platform_drvdata *arche_pdata)
250343
{
251344
unsigned long flags;
@@ -280,9 +373,11 @@ static ssize_t state_store(struct device *dev,
280373
struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev);
281374
int ret = 0;
282375

376+
mutex_lock(&arche_pdata->platform_state_mutex);
377+
283378
if (sysfs_streq(buf, "off")) {
284379
if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF)
285-
return count;
380+
goto exit;
286381

287382
/* If SVC goes down, bring down APB's as well */
288383
device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
@@ -291,19 +386,19 @@ static ssize_t state_store(struct device *dev,
291386

292387
} else if (sysfs_streq(buf, "active")) {
293388
if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE)
294-
return count;
389+
goto exit;
295390

296391
ret = arche_platform_coldboot_seq(arche_pdata);
297392

298393
assert_wakedetect(arche_pdata);
299394
} else if (sysfs_streq(buf, "standby")) {
300395
if (arche_pdata->state == ARCHE_PLATFORM_STATE_STANDBY)
301-
return count;
396+
goto exit;
302397

303398
dev_warn(arche_pdata->dev, "standby state not supported\n");
304399
} else if (sysfs_streq(buf, "fw_flashing")) {
305400
if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING)
306-
return count;
401+
goto exit;
307402

308403
/* First we want to make sure we power off everything
309404
* and then enter FW flashing state */
@@ -319,6 +414,8 @@ static ssize_t state_store(struct device *dev,
319414
ret = -EINVAL;
320415
}
321416

417+
exit:
418+
mutex_unlock(&arche_pdata->platform_state_mutex);
322419
return ret ? ret : count;
323420
}
324421

@@ -336,6 +433,8 @@ static ssize_t state_show(struct device *dev,
336433
return sprintf(buf, "standby\n");
337434
case ARCHE_PLATFORM_STATE_FW_FLASHING:
338435
return sprintf(buf, "fw_flashing\n");
436+
case ARCHE_PLATFORM_STATE_TIME_SYNC:
437+
return sprintf(buf, "time_sync\n");
339438
default:
340439
return sprintf(buf, "unknown state\n");
341440
}
@@ -349,11 +448,15 @@ static int arche_platform_pm_notifier(struct notifier_block *notifier,
349448
struct arche_platform_drvdata *arche_pdata =
350449
container_of(notifier, struct arche_platform_drvdata,
351450
pm_notifier);
451+
int ret = NOTIFY_DONE;
352452

453+
mutex_lock(&arche_pdata->platform_state_mutex);
353454
switch (pm_event) {
354455
case PM_SUSPEND_PREPARE:
355-
if (arche_pdata->state != ARCHE_PLATFORM_STATE_ACTIVE)
356-
return NOTIFY_STOP;
456+
if (arche_pdata->state != ARCHE_PLATFORM_STATE_ACTIVE) {
457+
ret = NOTIFY_STOP;
458+
break;
459+
}
357460
device_for_each_child(arche_pdata->dev, NULL, apb_poweroff);
358461
arche_platform_poweroff_seq(arche_pdata);
359462
break;
@@ -364,8 +467,9 @@ static int arche_platform_pm_notifier(struct notifier_block *notifier,
364467
default:
365468
break;
366469
}
470+
mutex_unlock(&arche_pdata->platform_state_mutex);
367471

368-
return NOTIFY_DONE;
472+
return ret;
369473
}
370474

371475
static int arche_platform_probe(struct platform_device *pdev)
@@ -468,6 +572,7 @@ static int arche_platform_probe(struct platform_device *pdev)
468572
arche_pdata->dev = &pdev->dev;
469573

470574
spin_lock_init(&arche_pdata->wake_lock);
575+
mutex_init(&arche_pdata->platform_state_mutex);
471576
arche_pdata->wake_detect_irq =
472577
gpio_to_irq(arche_pdata->wake_detect_gpio);
473578

@@ -489,6 +594,7 @@ static int arche_platform_probe(struct platform_device *pdev)
489594
return ret;
490595
}
491596

597+
mutex_lock(&arche_pdata->platform_state_mutex);
492598
ret = arche_platform_coldboot_seq(arche_pdata);
493599
if (ret) {
494600
dev_err(dev, "Failed to cold boot svc %d\n", ret);
@@ -505,6 +611,8 @@ static int arche_platform_probe(struct platform_device *pdev)
505611

506612
arche_pdata->pm_notifier.notifier_call = arche_platform_pm_notifier;
507613
ret = register_pm_notifier(&arche_pdata->pm_notifier);
614+
mutex_unlock(&arche_pdata->platform_state_mutex);
615+
508616
if (ret) {
509617
dev_err(dev, "failed to register pm notifier %d\n", ret);
510618
goto err_populate;
@@ -516,6 +624,7 @@ static int arche_platform_probe(struct platform_device *pdev)
516624
err_populate:
517625
arche_platform_poweroff_seq(arche_pdata);
518626
err_coldboot:
627+
mutex_unlock(&arche_pdata->platform_state_mutex);
519628
device_remove_file(&pdev->dev, &dev_attr_state);
520629
return ret;
521630
}

drivers/staging/greybus/arche_platform.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ enum arche_platform_state {
1515
ARCHE_PLATFORM_STATE_ACTIVE,
1616
ARCHE_PLATFORM_STATE_STANDBY,
1717
ARCHE_PLATFORM_STATE_FW_FLASHING,
18+
ARCHE_PLATFORM_STATE_TIME_SYNC,
1819
};
1920

21+
int arche_platform_change_state(enum arche_platform_state state);
2022

2123
int __init arche_apb_init(void);
2224
void __exit arche_apb_exit(void);

0 commit comments

Comments
 (0)