mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
apple_gmux: Add support for newer hardware
New gmux devices have a different method for accessing the registers. Update the driver to cope. Incorporates feedback from Bernhard Froemel. Signed-off-by: Matthew Garrett <mjg@redhat.com> Cc: Bernhard Froemel <froemel@vmars.tuwien.ac.at> Cc: Seth Forshee <seth.forshee@canonical.com>
This commit is contained in:
parent
7e30ed6bdd
commit
96ff705638
1 changed files with 165 additions and 14 deletions
|
@ -18,12 +18,15 @@
|
||||||
#include <linux/pnp.h>
|
#include <linux/pnp.h>
|
||||||
#include <linux/apple_bl.h>
|
#include <linux/apple_bl.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <acpi/video.h>
|
#include <acpi/video.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
struct apple_gmux_data {
|
struct apple_gmux_data {
|
||||||
unsigned long iostart;
|
unsigned long iostart;
|
||||||
unsigned long iolen;
|
unsigned long iolen;
|
||||||
|
bool indexed;
|
||||||
|
struct mutex index_lock;
|
||||||
|
|
||||||
struct backlight_device *bdev;
|
struct backlight_device *bdev;
|
||||||
};
|
};
|
||||||
|
@ -45,6 +48,9 @@ struct apple_gmux_data {
|
||||||
#define GMUX_PORT_DISCRETE_POWER 0x50
|
#define GMUX_PORT_DISCRETE_POWER 0x50
|
||||||
#define GMUX_PORT_MAX_BRIGHTNESS 0x70
|
#define GMUX_PORT_MAX_BRIGHTNESS 0x70
|
||||||
#define GMUX_PORT_BRIGHTNESS 0x74
|
#define GMUX_PORT_BRIGHTNESS 0x74
|
||||||
|
#define GMUX_PORT_VALUE 0xc2
|
||||||
|
#define GMUX_PORT_READ 0xd0
|
||||||
|
#define GMUX_PORT_WRITE 0xd4
|
||||||
|
|
||||||
#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
|
#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
|
||||||
|
|
||||||
|
@ -59,24 +65,24 @@ struct apple_gmux_data {
|
||||||
#define GMUX_BRIGHTNESS_MASK 0x00ffffff
|
#define GMUX_BRIGHTNESS_MASK 0x00ffffff
|
||||||
#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK
|
#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK
|
||||||
|
|
||||||
static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
|
static u8 gmux_pio_read8(struct apple_gmux_data *gmux_data, int port)
|
||||||
{
|
{
|
||||||
return inb(gmux_data->iostart + port);
|
return inb(gmux_data->iostart + port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port,
|
static void gmux_pio_write8(struct apple_gmux_data *gmux_data, int port,
|
||||||
u8 val)
|
u8 val)
|
||||||
{
|
{
|
||||||
outb(val, gmux_data->iostart + port);
|
outb(val, gmux_data->iostart + port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
|
static u32 gmux_pio_read32(struct apple_gmux_data *gmux_data, int port)
|
||||||
{
|
{
|
||||||
return inl(gmux_data->iostart + port);
|
return inl(gmux_data->iostart + port);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 gmux_write32(struct apple_gmux_data *gmux_data, int port,
|
static void gmux_pio_write32(struct apple_gmux_data *gmux_data, int port,
|
||||||
u32 val)
|
u32 val)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u8 tmpval;
|
u8 tmpval;
|
||||||
|
@ -87,6 +93,144 @@ static inline u32 gmux_write32(struct apple_gmux_data *gmux_data, int port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int gmux_index_wait_ready(struct apple_gmux_data *gmux_data)
|
||||||
|
{
|
||||||
|
int i = 200;
|
||||||
|
u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
|
||||||
|
|
||||||
|
while (i && (gwr & 0x01)) {
|
||||||
|
inb(gmux_data->iostart + GMUX_PORT_READ);
|
||||||
|
gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
|
||||||
|
udelay(100);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gmux_index_wait_complete(struct apple_gmux_data *gmux_data)
|
||||||
|
{
|
||||||
|
int i = 200;
|
||||||
|
u8 gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
|
||||||
|
|
||||||
|
while (i && !(gwr & 0x01)) {
|
||||||
|
gwr = inb(gmux_data->iostart + GMUX_PORT_WRITE);
|
||||||
|
udelay(100);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gwr & 0x01)
|
||||||
|
inb(gmux_data->iostart + GMUX_PORT_READ);
|
||||||
|
|
||||||
|
return !!i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 gmux_index_read8(struct apple_gmux_data *gmux_data, int port)
|
||||||
|
{
|
||||||
|
u8 val;
|
||||||
|
|
||||||
|
mutex_lock(&gmux_data->index_lock);
|
||||||
|
outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
|
||||||
|
gmux_index_wait_ready(gmux_data);
|
||||||
|
val = inb(gmux_data->iostart + GMUX_PORT_VALUE);
|
||||||
|
mutex_unlock(&gmux_data->index_lock);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gmux_index_write8(struct apple_gmux_data *gmux_data, int port,
|
||||||
|
u8 val)
|
||||||
|
{
|
||||||
|
mutex_lock(&gmux_data->index_lock);
|
||||||
|
outb(val, gmux_data->iostart + GMUX_PORT_VALUE);
|
||||||
|
gmux_index_wait_ready(gmux_data);
|
||||||
|
outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
|
||||||
|
gmux_index_wait_complete(gmux_data);
|
||||||
|
mutex_unlock(&gmux_data->index_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 gmux_index_read32(struct apple_gmux_data *gmux_data, int port)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
mutex_lock(&gmux_data->index_lock);
|
||||||
|
outb((port & 0xff), gmux_data->iostart + GMUX_PORT_READ);
|
||||||
|
gmux_index_wait_ready(gmux_data);
|
||||||
|
val = inl(gmux_data->iostart + GMUX_PORT_VALUE);
|
||||||
|
mutex_unlock(&gmux_data->index_lock);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gmux_index_write32(struct apple_gmux_data *gmux_data, int port,
|
||||||
|
u32 val)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
u8 tmpval;
|
||||||
|
|
||||||
|
mutex_lock(&gmux_data->index_lock);
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
tmpval = (val >> (i * 8)) & 0xff;
|
||||||
|
outb(tmpval, gmux_data->iostart + GMUX_PORT_VALUE + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
gmux_index_wait_ready(gmux_data);
|
||||||
|
outb(port & 0xff, gmux_data->iostart + GMUX_PORT_WRITE);
|
||||||
|
gmux_index_wait_complete(gmux_data);
|
||||||
|
mutex_unlock(&gmux_data->index_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
|
||||||
|
{
|
||||||
|
if (gmux_data->indexed)
|
||||||
|
return gmux_index_read8(gmux_data, port);
|
||||||
|
else
|
||||||
|
return gmux_pio_read8(gmux_data, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gmux_write8(struct apple_gmux_data *gmux_data, int port, u8 val)
|
||||||
|
{
|
||||||
|
if (gmux_data->indexed)
|
||||||
|
gmux_index_write8(gmux_data, port, val);
|
||||||
|
else
|
||||||
|
gmux_pio_write8(gmux_data, port, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
|
||||||
|
{
|
||||||
|
if (gmux_data->indexed)
|
||||||
|
return gmux_index_read32(gmux_data, port);
|
||||||
|
else
|
||||||
|
return gmux_pio_read32(gmux_data, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gmux_write32(struct apple_gmux_data *gmux_data, int port,
|
||||||
|
u32 val)
|
||||||
|
{
|
||||||
|
if (gmux_data->indexed)
|
||||||
|
gmux_index_write32(gmux_data, port, val);
|
||||||
|
else
|
||||||
|
gmux_pio_write32(gmux_data, port, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
|
||||||
|
{
|
||||||
|
u16 val;
|
||||||
|
|
||||||
|
outb(0xaa, gmux_data->iostart + 0xcc);
|
||||||
|
outb(0x55, gmux_data->iostart + 0xcd);
|
||||||
|
outb(0x00, gmux_data->iostart + 0xce);
|
||||||
|
|
||||||
|
val = inb(gmux_data->iostart + 0xcc) |
|
||||||
|
(inb(gmux_data->iostart + 0xcd) << 8);
|
||||||
|
|
||||||
|
if (val == 0x55aa)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int gmux_get_brightness(struct backlight_device *bd)
|
static int gmux_get_brightness(struct backlight_device *bd)
|
||||||
{
|
{
|
||||||
struct apple_gmux_data *gmux_data = bl_get_data(bd);
|
struct apple_gmux_data *gmux_data = bl_get_data(bd);
|
||||||
|
@ -150,22 +294,29 @@ static int __devinit gmux_probe(struct pnp_dev *pnp,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On some machines the gmux is in ACPI even thought the machine
|
* Invalid version information may indicate either that the gmux
|
||||||
* doesn't really have a gmux. Check for invalid version information
|
* device isn't present or that it's a new one that uses indexed
|
||||||
* to detect this.
|
* io
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
|
ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
|
||||||
ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
|
ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
|
||||||
ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
|
ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
|
||||||
if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
|
if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
|
||||||
pr_info("gmux device not present\n");
|
if (gmux_is_indexed(gmux_data)) {
|
||||||
ret = -ENODEV;
|
mutex_init(&gmux_data->index_lock);
|
||||||
goto err_release;
|
gmux_data->indexed = true;
|
||||||
|
} else {
|
||||||
|
pr_info("gmux device not present\n");
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto err_release;
|
||||||
|
}
|
||||||
|
pr_info("Found indexed gmux\n");
|
||||||
|
} else {
|
||||||
|
pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
|
||||||
|
ver_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
|
|
||||||
ver_release);
|
|
||||||
|
|
||||||
memset(&props, 0, sizeof(props));
|
memset(&props, 0, sizeof(props));
|
||||||
props.type = BACKLIGHT_PLATFORM;
|
props.type = BACKLIGHT_PLATFORM;
|
||||||
props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
|
props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
|
||||||
|
|
Loading…
Reference in a new issue