Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49a11dea authored by malattia@linux.it's avatar malattia@linux.it Committed by Len Brown
Browse files

sony-laptop: additional platform attributes coming from SNY6001



Register additional platform attributes coming from the SPIC (sonypi) driver.

Signed-off-by: default avatarMattia Dongili <malattia@linux.it>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 1549ee6f
Loading
Loading
Loading
Loading
+204 −1
Original line number Diff line number Diff line
@@ -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);