-
Notifications
You must be signed in to change notification settings - Fork 5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: popcornmix <popcornmix@gmail.com> BCM270x: power: Change initcall level to subsys Load ordering of modules are determined by the initcall used. If it's the same initcall level, makefile ordering decides. Now that the mailbox driver is being moved, it's no longer placed before the power driver by the linker. So use a later initcall level to let the mailbox driver load first. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> BCM270x: Move power module Make the power module available on ARCH_BCM2835 by moving it. The module turns on USB power making it possible to boot ARCH_BCM2835 directly with the VC bootloader. Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
- Loading branch information
1 parent
e9ee97a
commit 081ebd4
Showing
6 changed files
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# | ||
# BCM2835 Soc drivers | ||
# | ||
config BCM2708_POWER | ||
tristate "BCM2708 legacy power driver" | ||
depends on (ARCH_BCM2708 || ARCH_BCM2709 || ARCH_BCM2835) && BCM2708_MBOX | ||
default y | ||
help | ||
Turns on USB power and provides an API for controlling power. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
obj-$(CONFIG_BCM2708_POWER) += bcm2708-power.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
/* | ||
* linux/arch/arm/mach-bcm2708/power.c | ||
* | ||
* Copyright (C) 2010 Broadcom | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
* | ||
* This device provides a shared mechanism for controlling the power to | ||
* VideoCore subsystems. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/semaphore.h> | ||
#include <linux/bug.h> | ||
#include <linux/platform_data/mailbox-bcm2708.h> | ||
#include <soc/bcm2835/power.h> | ||
|
||
#define DRIVER_NAME "bcm2708_power" | ||
|
||
#define BCM_POWER_MAXCLIENTS 4 | ||
#define BCM_POWER_NOCLIENT (1<<31) | ||
|
||
/* Some drivers expect there devices to be permanently powered */ | ||
|
||
#ifdef CONFIG_USB | ||
#define BCM_POWER_ALWAYS_ON (BCM_POWER_USB) | ||
#endif | ||
|
||
#if 1 | ||
#define DPRINTK printk | ||
#else | ||
#define DPRINTK if (0) printk | ||
#endif | ||
|
||
struct state_struct { | ||
uint32_t global_request; | ||
uint32_t client_request[BCM_POWER_MAXCLIENTS]; | ||
struct semaphore client_mutex; | ||
struct semaphore mutex; | ||
} g_state; | ||
|
||
int bcm_power_open(BCM_POWER_HANDLE_T *handle) | ||
{ | ||
BCM_POWER_HANDLE_T i; | ||
int ret = -EBUSY; | ||
|
||
down(&g_state.client_mutex); | ||
|
||
for (i = 0; i < BCM_POWER_MAXCLIENTS; i++) { | ||
if (g_state.client_request[i] == BCM_POWER_NOCLIENT) { | ||
g_state.client_request[i] = BCM_POWER_NONE; | ||
*handle = i; | ||
ret = 0; | ||
break; | ||
} | ||
} | ||
|
||
up(&g_state.client_mutex); | ||
|
||
DPRINTK("bcm_power_open() -> %d\n", *handle); | ||
|
||
return ret; | ||
} | ||
EXPORT_SYMBOL_GPL(bcm_power_open); | ||
|
||
int bcm_power_request(BCM_POWER_HANDLE_T handle, uint32_t request) | ||
{ | ||
int rc = 0; | ||
|
||
DPRINTK("bcm_power_request(%d, %x)\n", handle, request); | ||
|
||
if ((handle < BCM_POWER_MAXCLIENTS) && | ||
(g_state.client_request[handle] != BCM_POWER_NOCLIENT)) { | ||
if (down_interruptible(&g_state.mutex) != 0) { | ||
DPRINTK("bcm_power_request -> interrupted\n"); | ||
return -EINTR; | ||
} | ||
|
||
if (request != g_state.client_request[handle]) { | ||
uint32_t others_request = 0; | ||
uint32_t global_request; | ||
BCM_POWER_HANDLE_T i; | ||
|
||
for (i = 0; i < BCM_POWER_MAXCLIENTS; i++) { | ||
if (i != handle) | ||
others_request |= | ||
g_state.client_request[i]; | ||
} | ||
others_request &= ~BCM_POWER_NOCLIENT; | ||
|
||
global_request = request | others_request; | ||
if (global_request != g_state.global_request) { | ||
uint32_t actual; | ||
|
||
/* Send a request to VideoCore */ | ||
bcm_mailbox_write(MBOX_CHAN_POWER, | ||
global_request << 4); | ||
|
||
/* Wait for a response during power-up */ | ||
if (global_request & ~g_state.global_request) { | ||
rc = bcm_mailbox_read(MBOX_CHAN_POWER, | ||
&actual); | ||
DPRINTK | ||
("bcm_mailbox_read -> %08x, %d\n", | ||
actual, rc); | ||
actual >>= 4; | ||
} else { | ||
rc = 0; | ||
actual = global_request; | ||
} | ||
|
||
if (rc == 0) { | ||
if (actual != global_request) { | ||
printk(KERN_ERR | ||
"%s: prev global %x, new global %x, actual %x, request %x, others_request %x\n", | ||
__func__, | ||
g_state.global_request, | ||
global_request, actual, request, others_request); | ||
/* A failure */ | ||
BUG_ON((others_request & actual) | ||
!= others_request); | ||
request &= actual; | ||
rc = -EIO; | ||
} | ||
|
||
g_state.global_request = actual; | ||
g_state.client_request[handle] = | ||
request; | ||
} | ||
} | ||
} | ||
up(&g_state.mutex); | ||
} else { | ||
rc = -EINVAL; | ||
} | ||
DPRINTK("bcm_power_request -> %d\n", rc); | ||
return rc; | ||
} | ||
EXPORT_SYMBOL_GPL(bcm_power_request); | ||
|
||
int bcm_power_close(BCM_POWER_HANDLE_T handle) | ||
{ | ||
int rc; | ||
|
||
DPRINTK("bcm_power_close(%d)\n", handle); | ||
|
||
rc = bcm_power_request(handle, BCM_POWER_NONE); | ||
if (rc == 0) | ||
g_state.client_request[handle] = BCM_POWER_NOCLIENT; | ||
|
||
return rc; | ||
} | ||
EXPORT_SYMBOL_GPL(bcm_power_close); | ||
|
||
static int __init bcm_power_init(void) | ||
{ | ||
#if defined(BCM_POWER_ALWAYS_ON) | ||
BCM_POWER_HANDLE_T always_on_handle; | ||
#endif | ||
int rc = 0; | ||
int i; | ||
|
||
printk(KERN_INFO "bcm_power: Broadcom power driver\n"); | ||
bcm_mailbox_write(MBOX_CHAN_POWER, 0); | ||
|
||
for (i = 0; i < BCM_POWER_MAXCLIENTS; i++) | ||
g_state.client_request[i] = BCM_POWER_NOCLIENT; | ||
|
||
sema_init(&g_state.client_mutex, 1); | ||
sema_init(&g_state.mutex, 1); | ||
|
||
g_state.global_request = 0; | ||
|
||
#if defined(BCM_POWER_ALWAYS_ON) | ||
if (BCM_POWER_ALWAYS_ON) { | ||
bcm_power_open(&always_on_handle); | ||
bcm_power_request(always_on_handle, BCM_POWER_ALWAYS_ON); | ||
} | ||
#endif | ||
|
||
return rc; | ||
} | ||
|
||
static void __exit bcm_power_exit(void) | ||
{ | ||
bcm_mailbox_write(MBOX_CHAN_POWER, 0); | ||
} | ||
|
||
/* | ||
* Load after the mailbox driver is initialized (arch_initcall), | ||
* but before depending drivers (module_init). | ||
*/ | ||
subsys_initcall(bcm_power_init); | ||
module_exit(bcm_power_exit); | ||
|
||
MODULE_AUTHOR("Phil Elwell"); | ||
MODULE_DESCRIPTION("Interface to BCM2708 power management"); | ||
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* Copyright (C) 2010 Broadcom | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
* | ||
* This device provides a shared mechanism for controlling the power to | ||
* VideoCore subsystems. | ||
*/ | ||
|
||
#ifndef _BCM2708_POWER_H | ||
#define _BCM2708_POWER_H | ||
|
||
#include <linux/types.h> | ||
|
||
/* Use meaningful names on each side */ | ||
#ifdef __VIDEOCORE__ | ||
#define PREFIX(x) ARM_##x | ||
#else | ||
#define PREFIX(x) BCM_##x | ||
#endif | ||
|
||
enum { | ||
PREFIX(POWER_SDCARD_BIT), | ||
PREFIX(POWER_UART_BIT), | ||
PREFIX(POWER_MINIUART_BIT), | ||
PREFIX(POWER_USB_BIT), | ||
PREFIX(POWER_I2C0_BIT), | ||
PREFIX(POWER_I2C1_BIT), | ||
PREFIX(POWER_I2C2_BIT), | ||
PREFIX(POWER_SPI_BIT), | ||
PREFIX(POWER_CCP2TX_BIT), | ||
PREFIX(POWER_DSI_BIT), | ||
|
||
PREFIX(POWER_MAX) | ||
}; | ||
|
||
enum { | ||
PREFIX(POWER_SDCARD) = (1 << PREFIX(POWER_SDCARD_BIT)), | ||
PREFIX(POWER_UART) = (1 << PREFIX(POWER_UART_BIT)), | ||
PREFIX(POWER_MINIUART) = (1 << PREFIX(POWER_MINIUART_BIT)), | ||
PREFIX(POWER_USB) = (1 << PREFIX(POWER_USB_BIT)), | ||
PREFIX(POWER_I2C0) = (1 << PREFIX(POWER_I2C0_BIT)), | ||
PREFIX(POWER_I2C1_MASK) = (1 << PREFIX(POWER_I2C1_BIT)), | ||
PREFIX(POWER_I2C2_MASK) = (1 << PREFIX(POWER_I2C2_BIT)), | ||
PREFIX(POWER_SPI_MASK) = (1 << PREFIX(POWER_SPI_BIT)), | ||
PREFIX(POWER_CCP2TX_MASK) = (1 << PREFIX(POWER_CCP2TX_BIT)), | ||
PREFIX(POWER_DSI) = (1 << PREFIX(POWER_DSI_BIT)), | ||
|
||
PREFIX(POWER_MASK) = (1 << PREFIX(POWER_MAX)) - 1, | ||
PREFIX(POWER_NONE) = 0 | ||
}; | ||
|
||
typedef unsigned int BCM_POWER_HANDLE_T; | ||
|
||
extern int bcm_power_open(BCM_POWER_HANDLE_T *handle); | ||
extern int bcm_power_request(BCM_POWER_HANDLE_T handle, uint32_t request); | ||
extern int bcm_power_close(BCM_POWER_HANDLE_T handle); | ||
|
||
#endif |