• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/arch/arm/plat-brcm/
1/*
2 * Northstar coma mode.
3 *
4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: hndcoma.c 406135 2013-06-06 04:57:34Z $
19 */
20
21#include <linux/proc_fs.h>
22#include <typedefs.h>
23#include <bcmutils.h>
24#include <siutils.h>
25#include <bcmdevs.h>
26#include <bcmnvram.h>
27#include <asm/uaccess.h>
28#include <linux/platform_device.h>
29
30#define DMU_BASE 0x1800c000
31/* Offset */
32#define CRU_INTERRUPT 0x18c
33#define PCU_AOPC_CONTROL 0x20
34#define PVTMON_CONTROL0 0x2c0
35#define CRU_RESET 0x184
36
37#define MAX_COMA_SLEEP_TIME 0x003fffe0
38
39/* Global SB handle */
40extern si_t *bcm947xx_sih;
41extern spinlock_t bcm947xx_sih_lock;
42
43/* Convenience */
44#define sih bcm947xx_sih
45#define sih_lock bcm947xx_sih_lock
46
47static uint32 dmu_base;
48static struct delayed_work coma_work;
49static struct platform_device *coma_pdev;
50
51static void coma_gpioout(uint32 gpio);
52
53static void
54coma_gpioout(uint32 gpio)
55{
56	int enable_gpio_mask;
57
58	enable_gpio_mask = 1 << gpio;
59
60	/* low active */
61	si_gpioout(sih, enable_gpio_mask, 0, GPIO_DRV_PRIORITY);
62	si_gpioouten(sih, enable_gpio_mask, enable_gpio_mask, GPIO_DRV_PRIORITY);
63}
64
65static void
66coma_polling(struct work_struct *work)
67{
68	uint32 cru_interrupt;
69
70	cru_interrupt = readl(dmu_base + CRU_INTERRUPT);
71	if (cru_interrupt & 0x01) {
72		coma_pdev = platform_device_register_simple("coma_dev", 0, NULL, 0);
73		return;
74	}
75	schedule_delayed_work(&coma_work, msecs_to_jiffies(1000));
76}
77
78static int
79coma_write_proc(struct file *file, const char __user *buf,
80	unsigned long count, void *data)
81{
82	char *buffer, *var;
83	uint32 pcu_aopc_control;
84	uint32 pvtmon_control0;
85	uint32 gpio;
86	uint32 sleep_time;
87
88	buffer = kmalloc(count + 1, GFP_KERNEL);
89	if (!buffer) {
90		printk("%s: kmalloc failed.\n", __FUNCTION__);
91		goto out;
92	}
93
94	if (copy_from_user(buffer, buf, count)) {
95		printk("%s: copy_from_user failed.\n", __FUNCTION__);
96		goto out;
97	}
98
99	/* enter coma mode */
100	if (buffer[0] == '2') {
101		/* PVT monitor power-down */
102		pvtmon_control0 = readl(dmu_base + PVTMON_CONTROL0) | 0x1;
103		writel(pvtmon_control0, dmu_base + PVTMON_CONTROL0);
104
105		/* Put ROBOSW, USBPHY, OPT, PVTMON in reset mode */
106		writel(0x6, dmu_base + CRU_RESET);
107
108		/* Drive GPIO pin to low to disable on-board switching regulator */
109		gpio = getgpiopin(NULL, "coma_swreg", GPIO_PIN_NOTDEFINED);
110		if (gpio != GPIO_PIN_NOTDEFINED) {
111			coma_gpioout(gpio);
112		}
113
114		/* Clear bit0 (PWR_DIS_LATCH_EN) of PCU_AOPC_CONTROL */
115		pcu_aopc_control = readl(dmu_base + PCU_AOPC_CONTROL);
116		pcu_aopc_control &= 0xfffffffe;
117		writel(pcu_aopc_control, dmu_base + PCU_AOPC_CONTROL);
118
119		/* set timer to auto-wakeup */
120		pcu_aopc_control = readl(dmu_base + PCU_AOPC_CONTROL);
121		var = getvar(NULL, "coma_sleep_time");
122		if (var)
123			sleep_time = bcm_strtoul(var, NULL, 0);
124		else
125			sleep_time = 0;
126		sleep_time = sleep_time << 5;
127		if ((sleep_time > 0) && (sleep_time <= MAX_COMA_SLEEP_TIME))
128			pcu_aopc_control |= sleep_time;
129		else
130			pcu_aopc_control |= MAX_COMA_SLEEP_TIME;
131
132		/* Config power down setting */
133		pcu_aopc_control |= 0x8040001f;
134		writel(pcu_aopc_control, dmu_base + PCU_AOPC_CONTROL);
135	} else if (buffer[0] == '0') {
136		/* cancel polling work */
137		cancel_delayed_work(&coma_work);
138	} else if (buffer[0] == '1') {
139		/* resume polling work */
140		schedule_delayed_work(&coma_work, msecs_to_jiffies(1000));
141	}
142out:
143	if (buffer)
144		kfree(buffer);
145
146	return count;
147}
148
149static void __init
150coma_proc_init(void)
151{
152	struct proc_dir_entry *coma_proc_dir, *coma;
153	char *var;
154	uint32 coma_disabled;
155
156	var = getvar(NULL, "coma_disable");
157	if (var) {
158		coma_disabled = bcm_strtoul(var, NULL, 0);
159		if (coma_disabled == 1)
160			return;
161	}
162
163	coma_proc_dir = proc_mkdir("bcm947xx", NULL);
164
165	if (!coma_proc_dir) {
166		printk(KERN_ERR "%s: Create proc directory failed.\n", __FUNCTION__);
167		return;
168	}
169
170	coma = create_proc_entry("bcm947xx/coma", 0, NULL);
171	if (!coma) {
172		printk(KERN_ERR "%s: Create proc entry failed.\n", __FUNCTION__);
173		return;
174	}
175
176	dmu_base = (uint32)REG_MAP(DMU_BASE, 4096);
177	coma->write_proc = coma_write_proc;
178
179	INIT_DELAYED_WORK(&coma_work, coma_polling);
180	schedule_delayed_work(&coma_work, msecs_to_jiffies(1000));
181}
182
183static void __exit
184coma_proc_exit(void)
185{
186	REG_UNMAP((void *)dmu_base);
187	cancel_delayed_work(&coma_work);
188	remove_proc_entry("bcm947xx/coma", NULL);
189}
190
191module_init(coma_proc_init);
192module_exit(coma_proc_exit);
193