diff options
author | malattia@linux.it <malattia@linux.it> | 2007-04-09 19:28:56 +0200 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-04-10 16:01:19 -0400 |
commit | 49a11deade3c1d9e2d7c88d25899b3a9174d048e (patch) | |
tree | 61088ddf15aac99aea8343d070393ade5d3d17e9 /drivers/misc | |
parent | 1549ee6fb122400c0767b5f3da2c42abbc4f750a (diff) |
sony-laptop: additional platform attributes coming from SNY6001
Register additional platform attributes coming from the SPIC (sonypi) driver.
Signed-off-by: Mattia Dongili <malattia@linux.it>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/sony-laptop.c | 205 |
1 files changed, 204 insertions, 1 deletions
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index cf8d7927dc5..3e8f3aaa092 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -774,7 +774,8 @@ static int sony_nc_add(struct acpi_device *device) } - if (sony_pf_add()) + result = sony_pf_add(); + if (result) goto outbacklight; /* create sony_pf sysfs attributes related to the SNC device */ @@ -903,6 +904,8 @@ struct sony_pic_irq { struct sony_pic_dev { int model; + u8 camera_power; + u8 bluetooth_power; struct acpi_device *acpi_dev; struct sony_pic_irq *cur_irq; struct sony_pic_ioport *cur_ioport; @@ -1181,6 +1184,186 @@ static u8 sony_pic_call2(u8 dev, u8 fn) return v1; } +static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) +{ + u8 v1; + + wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); + outb(dev, spic_dev.cur_ioport->io.minimum + 4); + wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); + outb(fn, spic_dev.cur_ioport->io.minimum); + wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); + outb(v, spic_dev.cur_ioport->io.minimum); + v1 = inb_p(spic_dev.cur_ioport->io.minimum); + dprintk("sony_pic_call3: 0x%.4x\n", v1); + return v1; +} + +/* camera tests and poweron/poweroff */ +#define SONYPI_CAMERA_PICTURE 5 +#define SONYPI_CAMERA_MUTE_MASK 0x40 +#define SONYPI_CAMERA_CONTROL 0x10 +#define SONYPI_CAMERA_STATUS 7 +#define SONYPI_CAMERA_STATUS_READY 0x2 +#define SONYPI_CAMERA_STATUS_POSITION 0x4 + +static int sony_pic_camera_ready(void) +{ + u8 v; + + v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS); + return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); +} + +static void sony_pic_camera_off(void) +{ + wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, + SONYPI_CAMERA_MUTE_MASK), + ITERATIONS_SHORT); + + if (!spic_dev.camera_power) + return; + + sony_pic_call2(0x91, 0); + spic_dev.camera_power = 0; +} + +static void sony_pic_camera_on(void) +{ + int i, j; + + if (spic_dev.camera_power) + return; + + for (j = 5; j > 0; j--) { + + while (sony_pic_call2(0x91, 0x1)) + msleep(10); + sony_pic_call1(0x93); + + for (i = 400; i > 0; i--) { + if (sony_pic_camera_ready()) + break; + msleep(10); + } + if (i) + break; + } + + if (j == 0) { + printk(KERN_WARNING "sonypi: failed to power on camera\n"); + return; + } + + wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL, + 0x5a), + ITERATIONS_SHORT); + + spic_dev.camera_power = 1; +} + +static ssize_t sony_pic_camerapower_store(struct device *dev, + struct device_attribute *attr, + const char *buffer, size_t count) +{ + unsigned long value; + if (count > 31) + return -EINVAL; + + value = simple_strtoul(buffer, NULL, 10); + if (value) + sony_pic_camera_on(); + else + sony_pic_camera_off(); + + return count; +} + +static ssize_t sony_pic_camerapower_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + return snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.camera_power); +} + +/* bluetooth subsystem power state */ +static void sony_pic_set_bluetoothpower(u8 state) +{ + state = !!state; + if (spic_dev.bluetooth_power == state) + return; + sony_pic_call2(0x96, state); + sony_pic_call1(0x82); + spic_dev.bluetooth_power = state; +} + +static ssize_t sony_pic_bluetoothpower_store(struct device *dev, + struct device_attribute *attr, + const char *buffer, size_t count) +{ + unsigned long value; + if (count > 31) + return -EINVAL; + + value = simple_strtoul(buffer, NULL, 10); + sony_pic_set_bluetoothpower(value); + + return count; +} + +static ssize_t sony_pic_bluetoothpower_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + return snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power); +} + +/* fan speed */ +/* FAN0 information (reverse engineered from ACPI tables) */ +#define SONY_PIC_FAN0_STATUS 0x93 +static ssize_t sony_pic_fanspeed_store(struct device *dev, + struct device_attribute *attr, + const char *buffer, size_t count) +{ + unsigned long value; + if (count > 31) + return -EINVAL; + + value = simple_strtoul(buffer, NULL, 10); + if (ec_write(SONY_PIC_FAN0_STATUS, value)) + return -EIO; + + return count; +} + +static ssize_t sony_pic_fanspeed_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + u8 value = 0; + if (ec_read(SONY_PIC_FAN0_STATUS, &value)) + return -EIO; + + return snprintf(buffer, PAGE_SIZE, "%d\n", value); +} + +#define SPIC_ATTR(_name, _mode) \ +struct device_attribute spic_attr_##_name = __ATTR(_name, \ + _mode, sony_pic_## _name ##_show, \ + sony_pic_## _name ##_store) + +static SPIC_ATTR(camerapower, 0644); +static SPIC_ATTR(bluetoothpower, 0644); +static SPIC_ATTR(fanspeed, 0644); + +static struct attribute *spic_attributes[] = { + &spic_attr_camerapower.attr, + &spic_attr_bluetoothpower.attr, + &spic_attr_fanspeed.attr, + NULL +}; + +static struct attribute_group spic_attribute_group = { + .attrs = spic_attributes +}; + /* * ACPI callbacks */ @@ -1447,6 +1630,10 @@ static int sony_pic_remove(struct acpi_device *device, int type) sony_laptop_remove_input(); + /* pf attrs */ + sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group); + sony_pf_remove(); + list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { list_del(&io->list); kfree(io); @@ -1536,8 +1723,24 @@ static int sony_pic_add(struct acpi_device *device) goto err_free_irq; } + spic_dev.bluetooth_power = -1; + /* create device attributes */ + result = sony_pf_add(); + if (result) + goto err_disable_device; + + result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group); + if (result) + goto err_remove_pf; + return 0; +err_remove_pf: + sony_pf_remove(); + +err_disable_device: + sony_pic_disable(device); + err_free_irq: free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); |