text: /*
   * Copyright (c) 2016 Intel Corporation.
   *
   * SPDX-License-Identifier: Apache-2.0
   */
  
  #include <string.h>
  
  #include <zephyr.h>
  #include <kernel.h>
  #include <power.h>
  #include <device.h>
  #include <misc/printk.h>
  #include <power.h>
  #include <soc_power.h>
  #include <ipm.h>
  #include <ipm/ipm_quark_se.h>
  
  #define TASK_TIME_IN_SEC 5
  #define MAX_SUSPEND_DEVICE_COUNT 15
  
  static struct device *suspended_devices[MAX_SUSPEND_DEVICE_COUNT];
  static int suspend_device_count;
  static struct k_fifo fifo;
  static int post_ops_done;
  
  QUARK_SE_IPM_DEFINE(alarm_notification, 0, QUARK_SE_IPM_INBOUND);
  
  static void suspend_devices(void)
  {
  	for (int i = suspend_device_count - 1; i >= 0; i--) {
  		device_set_power_state(suspended_devices[i],
  				       DEVICE_PM_SUSPEND_STATE);
  	}
  }
  
  static void resume_devices(void)
  {
  	for (int i = 0; i < suspend_device_count; i++) {
  		device_set_power_state(suspended_devices[i],
  				       DEVICE_PM_ACTIVE_STATE);
  	}
  }
  
  int _sys_soc_suspend(s32_t ticks)
  {
  	post_ops_done = 0;
  
  	suspend_devices();
  
  	_sys_soc_set_power_state(SYS_POWER_STATE_DEEP_SLEEP);
  
  	if (!post_ops_done) {
  		post_ops_done = 1;
  		resume_devices();
  		_sys_soc_power_state_post_ops(SYS_POWER_STATE_DEEP_SLEEP);
  	}
  
  	return SYS_PM_DEEP_SLEEP;
  }
  
  void _sys_soc_resume(void)
  {
  	if (!post_ops_done) {
  		post_ops_done = 1;
  		_sys_soc_power_state_post_ops(SYS_POWER_STATE_DEEP_SLEEP);
  		resume_devices();
  	}
  }
  
  static void build_suspend_device_list(void)
  {
  	int i, devcount;
  	struct device *devices;
  
  	device_list_get(&devices, &devcount);
  	if (devcount > MAX_SUSPEND_DEVICE_COUNT) {
  		printk("Error: List of devices exceeds what we can track "
  		       "for suspend. Built: %d, Max: %d\n",
  		       devcount, MAX_SUSPEND_DEVICE_COUNT);
  		return;
  	}
  
  	suspend_device_count = 2;
  	for (i = 0; i < devcount; i++) {
  		if (!strcmp(devices[i].config->name, "arc_v2_irq_unit")) {
  			suspended_devices[0] = &devices[i];
  		} else if (!strcmp(devices[i].config->name, "sys_clock")) {
  			suspended_devices[1] = &devices[i];
  		} else {
  			suspended_devices[suspend_device_count++] = &devices[i];
  		}
  	}
  }
  
  void alarm_notification_handler(void *context, u32_t id,
  				volatile void *data)
  {
  	/* Unblock ARC application thread. */
  	k_fifo_put(&fifo, NULL);
  }
  
  void main(void)
  {
  	struct device *ipm;
  
  	printk("ARC: Quark SE PM Multicore Demo\n");
  
  	build_suspend_device_list();
  
  	k_fifo_init(&fifo);
  
  	ipm = device_get_binding("alarm_notification");
  	ipm_register_callback(ipm, alarm_notification_handler, NULL);
  	ipm_set_enabled(ipm, 1);
  
  	while (1) {
  		/* Simulate some task handling by busy waiting. */
  		printk("ARC: busy\n");
  		k_busy_wait(TASK_TIME_IN_SEC * 1000 * 1000);
  
  		printk("ARC: idle\n");
  		k_fifo_get(&fifo, K_FOREVER);
  	}
  }
  