aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/sony-laptop.c
diff options
context:
space:
mode:
authormalattia@linux.it <malattia@linux.it>2007-04-09 13:28:56 -0400
committerLen Brown <len.brown@intel.com>2007-04-10 16:01:19 -0400
commit49a11deade3c1d9e2d7c88d25899b3a9174d048e (patch)
tree61088ddf15aac99aea8343d070393ade5d3d17e9 /drivers/misc/sony-laptop.c
parent1549ee6fb122400c0767b5f3da2c42abbc4f750a (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/sony-laptop.c')
-rw-r--r--drivers/misc/sony-laptop.c205
1 files changed, 204 insertions, 1 deletions
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index cf8d7927dc5c..3e8f3aaa0923 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)
774 774
775 } 775 }
776 776
777 if (sony_pf_add()) 777 result = sony_pf_add();
778 if (result)
778 goto outbacklight; 779 goto outbacklight;
779 780
780 /* create sony_pf sysfs attributes related to the SNC device */ 781 /* create sony_pf sysfs attributes related to the SNC device */
@@ -903,6 +904,8 @@ struct sony_pic_irq {
903 904
904struct sony_pic_dev { 905struct sony_pic_dev {
905 int model; 906 int model;
907 u8 camera_power;
908 u8 bluetooth_power;
906 struct acpi_device *acpi_dev; 909 struct acpi_device *acpi_dev;
907 struct sony_pic_irq *cur_irq; 910 struct sony_pic_irq *cur_irq;
908 struct sony_pic_ioport *cur_ioport; 911 struct sony_pic_ioport *cur_ioport;
@@ -1181,6 +1184,186 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
1181 return v1; 1184 return v1;
1182} 1185}
1183 1186
1187static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
1188{
1189 u8 v1;
1190
1191 wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
1192 outb(dev, spic_dev.cur_ioport->io.minimum + 4);
1193 wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
1194 outb(fn, spic_dev.cur_ioport->io.minimum);
1195 wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
1196 outb(v, spic_dev.cur_ioport->io.minimum);
1197 v1 = inb_p(spic_dev.cur_ioport->io.minimum);
1198 dprintk("sony_pic_call3: 0x%.4x\n", v1);
1199 return v1;
1200}
1201
1202/* camera tests and poweron/poweroff */
1203#define SONYPI_CAMERA_PICTURE 5
1204#define SONYPI_CAMERA_MUTE_MASK 0x40
1205#define SONYPI_CAMERA_CONTROL 0x10
1206#define SONYPI_CAMERA_STATUS 7
1207#define SONYPI_CAMERA_STATUS_READY 0x2
1208#define SONYPI_CAMERA_STATUS_POSITION 0x4
1209
1210static int sony_pic_camera_ready(void)
1211{
1212 u8 v;
1213
1214 v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
1215 return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
1216}
1217
1218static void sony_pic_camera_off(void)
1219{
1220 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
1221 SONYPI_CAMERA_MUTE_MASK),
1222 ITERATIONS_SHORT);
1223
1224 if (!spic_dev.camera_power)
1225 return;
1226
1227 sony_pic_call2(0x91, 0);
1228 spic_dev.camera_power = 0;
1229}
1230
1231static void sony_pic_camera_on(void)
1232{
1233 int i, j;
1234
1235 if (spic_dev.camera_power)
1236 return;
1237
1238 for (j = 5; j > 0; j--) {
1239
1240 while (sony_pic_call2(0x91, 0x1))
1241 msleep(10);
1242 sony_pic_call1(0x93);
1243
1244 for (i = 400; i > 0; i--) {
1245 if (sony_pic_camera_ready())
1246 break;
1247 msleep(10);
1248 }
1249 if (i)
1250 break;
1251 }
1252
1253 if (j == 0) {
1254 printk(KERN_WARNING "sonypi: failed to power on camera\n");
1255 return;
1256 }
1257
1258 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
1259 0x5a),
1260 ITERATIONS_SHORT);
1261
1262 spic_dev.camera_power = 1;
1263}
1264
1265static ssize_t sony_pic_camerapower_store(struct device *dev,
1266 struct device_attribute *attr,
1267 const char *buffer, size_t count)
1268{
1269 unsigned long value;
1270 if (count > 31)
1271 return -EINVAL;
1272
1273 value = simple_strtoul(buffer, NULL, 10);
1274 if (value)
1275 sony_pic_camera_on();
1276 else
1277 sony_pic_camera_off();
1278
1279 return count;
1280}
1281
1282static ssize_t sony_pic_camerapower_show(struct device *dev,
1283 struct device_attribute *attr, char *buffer)
1284{
1285 return snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.camera_power);
1286}
1287
1288/* bluetooth subsystem power state */
1289static void sony_pic_set_bluetoothpower(u8 state)
1290{
1291 state = !!state;
1292 if (spic_dev.bluetooth_power == state)
1293 return;
1294 sony_pic_call2(0x96, state);
1295 sony_pic_call1(0x82);
1296 spic_dev.bluetooth_power = state;
1297}
1298
1299static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
1300 struct device_attribute *attr,
1301 const char *buffer, size_t count)
1302{
1303 unsigned long value;
1304 if (count > 31)
1305 return -EINVAL;
1306
1307 value = simple_strtoul(buffer, NULL, 10);
1308 sony_pic_set_bluetoothpower(value);
1309
1310 return count;
1311}
1312
1313static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
1314 struct device_attribute *attr, char *buffer)
1315{
1316 return snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
1317}
1318
1319/* fan speed */
1320/* FAN0 information (reverse engineered from ACPI tables) */
1321#define SONY_PIC_FAN0_STATUS 0x93
1322static ssize_t sony_pic_fanspeed_store(struct device *dev,
1323 struct device_attribute *attr,
1324 const char *buffer, size_t count)
1325{
1326 unsigned long value;
1327 if (count > 31)
1328 return -EINVAL;
1329
1330 value = simple_strtoul(buffer, NULL, 10);
1331 if (ec_write(SONY_PIC_FAN0_STATUS, value))
1332 return -EIO;
1333
1334 return count;
1335}
1336
1337static ssize_t sony_pic_fanspeed_show(struct device *dev,
1338 struct device_attribute *attr, char *buffer)
1339{
1340 u8 value = 0;
1341 if (ec_read(SONY_PIC_FAN0_STATUS, &value))
1342 return -EIO;
1343
1344 return snprintf(buffer, PAGE_SIZE, "%d\n", value);
1345}
1346
1347#define SPIC_ATTR(_name, _mode) \
1348struct device_attribute spic_attr_##_name = __ATTR(_name, \
1349 _mode, sony_pic_## _name ##_show, \
1350 sony_pic_## _name ##_store)
1351
1352static SPIC_ATTR(camerapower, 0644);
1353static SPIC_ATTR(bluetoothpower, 0644);
1354static SPIC_ATTR(fanspeed, 0644);
1355
1356static struct attribute *spic_attributes[] = {
1357 &spic_attr_camerapower.attr,
1358 &spic_attr_bluetoothpower.attr,
1359 &spic_attr_fanspeed.attr,
1360 NULL
1361};
1362
1363static struct attribute_group spic_attribute_group = {
1364 .attrs = spic_attributes
1365};
1366
1184/* 1367/*
1185 * ACPI callbacks 1368 * ACPI callbacks
1186 */ 1369 */
@@ -1447,6 +1630,10 @@ static int sony_pic_remove(struct acpi_device *device, int type)
1447 1630
1448 sony_laptop_remove_input(); 1631 sony_laptop_remove_input();
1449 1632
1633 /* pf attrs */
1634 sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
1635 sony_pf_remove();
1636
1450 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { 1637 list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
1451 list_del(&io->list); 1638 list_del(&io->list);
1452 kfree(io); 1639 kfree(io);
@@ -1536,8 +1723,24 @@ static int sony_pic_add(struct acpi_device *device)
1536 goto err_free_irq; 1723 goto err_free_irq;
1537 } 1724 }
1538 1725
1726 spic_dev.bluetooth_power = -1;
1727 /* create device attributes */
1728 result = sony_pf_add();
1729 if (result)
1730 goto err_disable_device;
1731
1732 result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
1733 if (result)
1734 goto err_remove_pf;
1735
1539 return 0; 1736 return 0;
1540 1737
1738err_remove_pf:
1739 sony_pf_remove();
1740
1741err_disable_device:
1742 sony_pic_disable(device);
1743
1541err_free_irq: 1744err_free_irq:
1542 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); 1745 free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
1543 1746