aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Smirnov <andrew.smirnov@gmail.com>2014-02-12 18:02:14 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-02-12 18:09:48 -0500
commite5fcd269c4599c4d224333b20e3ffd5e910d4db3 (patch)
tree60b33654aeff061f5b588d8d404101e79f7a3279
parentad7647d92f61c6e78bf6dc3804da1e2acf0515b6 (diff)
Input: ims-pcu - add commands supported by the new version of the FW
New version of the PCU firmware supports two new commands: - IMS_PCU_CMD_OFN_SET_CONFIG which allows to write data to the registers of one finger navigation(OFN) chip present on the device - IMS_PCU_CMD_OFN_GET_CONFIG which allows to read data form the registers of said chip. This commit adds two helper functions to use those commands and sysfs attributes to use them. It also exposes some OFN configuration parameters via sysfs. Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/misc/ims-pcu.c254
1 files changed, 248 insertions, 6 deletions
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index 5e8e90260037..5a736397d9c8 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -51,6 +51,8 @@ struct ims_pcu_backlight {
51#define IMS_PCU_BL_VERSION_LEN (9 + 1) 51#define IMS_PCU_BL_VERSION_LEN (9 + 1)
52#define IMS_PCU_BL_RESET_REASON_LEN (2 + 1) 52#define IMS_PCU_BL_RESET_REASON_LEN (2 + 1)
53 53
54#define IMS_PCU_PCU_B_DEVICE_ID 5
55
54#define IMS_PCU_BUF_SIZE 128 56#define IMS_PCU_BUF_SIZE 128
55 57
56struct ims_pcu { 58struct ims_pcu {
@@ -68,6 +70,9 @@ struct ims_pcu {
68 char bl_version[IMS_PCU_BL_VERSION_LEN]; 70 char bl_version[IMS_PCU_BL_VERSION_LEN];
69 char reset_reason[IMS_PCU_BL_RESET_REASON_LEN]; 71 char reset_reason[IMS_PCU_BL_RESET_REASON_LEN];
70 int update_firmware_status; 72 int update_firmware_status;
73 u8 device_id;
74
75 u8 ofn_reg_addr;
71 76
72 struct usb_interface *ctrl_intf; 77 struct usb_interface *ctrl_intf;
73 78
@@ -371,6 +376,8 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
371#define IMS_PCU_CMD_GET_DEVICE_ID 0xae 376#define IMS_PCU_CMD_GET_DEVICE_ID 0xae
372#define IMS_PCU_CMD_SPECIAL_INFO 0xb0 377#define IMS_PCU_CMD_SPECIAL_INFO 0xb0
373#define IMS_PCU_CMD_BOOTLOADER 0xb1 /* Pass data to bootloader */ 378#define IMS_PCU_CMD_BOOTLOADER 0xb1 /* Pass data to bootloader */
379#define IMS_PCU_CMD_OFN_SET_CONFIG 0xb3
380#define IMS_PCU_CMD_OFN_GET_CONFIG 0xb4
374 381
375/* PCU responses */ 382/* PCU responses */
376#define IMS_PCU_RSP_STATUS 0xc0 383#define IMS_PCU_RSP_STATUS 0xc0
@@ -389,6 +396,9 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
389#define IMS_PCU_RSP_GET_DEVICE_ID 0xce 396#define IMS_PCU_RSP_GET_DEVICE_ID 0xce
390#define IMS_PCU_RSP_SPECIAL_INFO 0xd0 397#define IMS_PCU_RSP_SPECIAL_INFO 0xd0
391#define IMS_PCU_RSP_BOOTLOADER 0xd1 /* Bootloader response */ 398#define IMS_PCU_RSP_BOOTLOADER 0xd1 /* Bootloader response */
399#define IMS_PCU_RSP_OFN_SET_CONFIG 0xd2
400#define IMS_PCU_RSP_OFN_GET_CONFIG 0xd3
401
392 402
393#define IMS_PCU_RSP_EVNT_BUTTONS 0xe0 /* Unsolicited, button state */ 403#define IMS_PCU_RSP_EVNT_BUTTONS 0xe0 /* Unsolicited, button state */
394#define IMS_PCU_GAMEPAD_MASK 0x0001ff80UL /* Bits 7 through 16 */ 404#define IMS_PCU_GAMEPAD_MASK 0x0001ff80UL /* Bits 7 through 16 */
@@ -1256,6 +1266,225 @@ static struct attribute_group ims_pcu_attr_group = {
1256 .attrs = ims_pcu_attrs, 1266 .attrs = ims_pcu_attrs,
1257}; 1267};
1258 1268
1269/* Support for a separate OFN attribute group */
1270
1271#define OFN_REG_RESULT_OFFSET 2
1272
1273static int ims_pcu_read_ofn_config(struct ims_pcu *pcu, u8 addr, u8 *data)
1274{
1275 int error;
1276 s16 result;
1277
1278 error = ims_pcu_execute_command(pcu, OFN_GET_CONFIG,
1279 &addr, sizeof(addr));
1280 if (error)
1281 return error;
1282
1283 result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
1284 if (result < 0)
1285 return -EIO;
1286
1287 /* We only need LSB */
1288 *data = pcu->cmd_buf[OFN_REG_RESULT_OFFSET];
1289 return 0;
1290}
1291
1292static int ims_pcu_write_ofn_config(struct ims_pcu *pcu, u8 addr, u8 data)
1293{
1294 u8 buffer[] = { addr, data };
1295 int error;
1296 s16 result;
1297
1298 error = ims_pcu_execute_command(pcu, OFN_SET_CONFIG,
1299 &buffer, sizeof(buffer));
1300 if (error)
1301 return error;
1302
1303 result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
1304 if (result < 0)
1305 return -EIO;
1306
1307 return 0;
1308}
1309
1310static ssize_t ims_pcu_ofn_reg_data_show(struct device *dev,
1311 struct device_attribute *dattr,
1312 char *buf)
1313{
1314 struct usb_interface *intf = to_usb_interface(dev);
1315 struct ims_pcu *pcu = usb_get_intfdata(intf);
1316 int error;
1317 u8 data;
1318
1319 mutex_lock(&pcu->cmd_mutex);
1320 error = ims_pcu_read_ofn_config(pcu, pcu->ofn_reg_addr, &data);
1321 mutex_unlock(&pcu->cmd_mutex);
1322
1323 if (error)
1324 return error;
1325
1326 return scnprintf(buf, PAGE_SIZE, "%x\n", data);
1327}
1328
1329static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev,
1330 struct device_attribute *dattr,
1331 const char *buf, size_t count)
1332{
1333 struct usb_interface *intf = to_usb_interface(dev);
1334 struct ims_pcu *pcu = usb_get_intfdata(intf);
1335 int error;
1336 u8 value;
1337
1338 error = kstrtou8(buf, 0, &value);
1339 if (error)
1340 return error;
1341
1342 mutex_lock(&pcu->cmd_mutex);
1343 error = ims_pcu_write_ofn_config(pcu, pcu->ofn_reg_addr, value);
1344 mutex_unlock(&pcu->cmd_mutex);
1345
1346 return error ?: count;
1347}
1348
1349static DEVICE_ATTR(reg_data, S_IRUGO | S_IWUSR,
1350 ims_pcu_ofn_reg_data_show, ims_pcu_ofn_reg_data_store);
1351
1352static ssize_t ims_pcu_ofn_reg_addr_show(struct device *dev,
1353 struct device_attribute *dattr,
1354 char *buf)
1355{
1356 struct usb_interface *intf = to_usb_interface(dev);
1357 struct ims_pcu *pcu = usb_get_intfdata(intf);
1358 int error;
1359
1360 mutex_lock(&pcu->cmd_mutex);
1361 error = scnprintf(buf, PAGE_SIZE, "%x\n", pcu->ofn_reg_addr);
1362 mutex_unlock(&pcu->cmd_mutex);
1363
1364 return error;
1365}
1366
1367static ssize_t ims_pcu_ofn_reg_addr_store(struct device *dev,
1368 struct device_attribute *dattr,
1369 const char *buf, size_t count)
1370{
1371 struct usb_interface *intf = to_usb_interface(dev);
1372 struct ims_pcu *pcu = usb_get_intfdata(intf);
1373 int error;
1374 u8 value;
1375
1376 error = kstrtou8(buf, 0, &value);
1377 if (error)
1378 return error;
1379
1380 mutex_lock(&pcu->cmd_mutex);
1381 pcu->ofn_reg_addr = value;
1382 mutex_unlock(&pcu->cmd_mutex);
1383
1384 return error ?: count;
1385}
1386
1387static DEVICE_ATTR(reg_addr, S_IRUGO | S_IWUSR,
1388 ims_pcu_ofn_reg_addr_show, ims_pcu_ofn_reg_addr_store);
1389
1390struct ims_pcu_ofn_bit_attribute {
1391 struct device_attribute dattr;
1392 u8 addr;
1393 u8 nr;
1394};
1395
1396static ssize_t ims_pcu_ofn_bit_show(struct device *dev,
1397 struct device_attribute *dattr,
1398 char *buf)
1399{
1400 struct usb_interface *intf = to_usb_interface(dev);
1401 struct ims_pcu *pcu = usb_get_intfdata(intf);
1402 struct ims_pcu_ofn_bit_attribute *attr =
1403 container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
1404 int error;
1405 u8 data;
1406
1407 mutex_lock(&pcu->cmd_mutex);
1408 error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
1409 mutex_unlock(&pcu->cmd_mutex);
1410
1411 if (error)
1412 return error;
1413
1414 return scnprintf(buf, PAGE_SIZE, "%d\n", !!(data & (1 << attr->nr)));
1415}
1416
1417static ssize_t ims_pcu_ofn_bit_store(struct device *dev,
1418 struct device_attribute *dattr,
1419 const char *buf, size_t count)
1420{
1421 struct usb_interface *intf = to_usb_interface(dev);
1422 struct ims_pcu *pcu = usb_get_intfdata(intf);
1423 struct ims_pcu_ofn_bit_attribute *attr =
1424 container_of(dattr, struct ims_pcu_ofn_bit_attribute, dattr);
1425 int error;
1426 int value;
1427 u8 data;
1428
1429 error = kstrtoint(buf, 0, &value);
1430 if (error)
1431 return error;
1432
1433 if (value > 1)
1434 return -EINVAL;
1435
1436 mutex_lock(&pcu->cmd_mutex);
1437
1438 error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
1439 if (!error) {
1440 if (value)
1441 data |= 1U << attr->nr;
1442 else
1443 data &= ~(1U << attr->nr);
1444
1445 error = ims_pcu_write_ofn_config(pcu, attr->addr, data);
1446 }
1447
1448 mutex_unlock(&pcu->cmd_mutex);
1449
1450 return error ?: count;
1451}
1452
1453#define IMS_PCU_OFN_BIT_ATTR(_field, _addr, _nr) \
1454struct ims_pcu_ofn_bit_attribute ims_pcu_ofn_attr_##_field = { \
1455 .dattr = __ATTR(_field, S_IWUSR | S_IRUGO, \
1456 ims_pcu_ofn_bit_show, ims_pcu_ofn_bit_store), \
1457 .addr = _addr, \
1458 .nr = _nr, \
1459}
1460
1461static IMS_PCU_OFN_BIT_ATTR(engine_enable, 0x60, 7);
1462static IMS_PCU_OFN_BIT_ATTR(speed_enable, 0x60, 6);
1463static IMS_PCU_OFN_BIT_ATTR(assert_enable, 0x60, 5);
1464static IMS_PCU_OFN_BIT_ATTR(xyquant_enable, 0x60, 4);
1465static IMS_PCU_OFN_BIT_ATTR(xyscale_enable, 0x60, 1);
1466
1467static IMS_PCU_OFN_BIT_ATTR(scale_x2, 0x63, 6);
1468static IMS_PCU_OFN_BIT_ATTR(scale_y2, 0x63, 7);
1469
1470static struct attribute *ims_pcu_ofn_attrs[] = {
1471 &dev_attr_reg_data.attr,
1472 &dev_attr_reg_addr.attr,
1473 &ims_pcu_ofn_attr_engine_enable.dattr.attr,
1474 &ims_pcu_ofn_attr_speed_enable.dattr.attr,
1475 &ims_pcu_ofn_attr_assert_enable.dattr.attr,
1476 &ims_pcu_ofn_attr_xyquant_enable.dattr.attr,
1477 &ims_pcu_ofn_attr_xyscale_enable.dattr.attr,
1478 &ims_pcu_ofn_attr_scale_x2.dattr.attr,
1479 &ims_pcu_ofn_attr_scale_y2.dattr.attr,
1480 NULL
1481};
1482
1483static struct attribute_group ims_pcu_ofn_attr_group = {
1484 .name = "ofn",
1485 .attrs = ims_pcu_ofn_attrs,
1486};
1487
1259static void ims_pcu_irq(struct urb *urb) 1488static void ims_pcu_irq(struct urb *urb)
1260{ 1489{
1261 struct ims_pcu *pcu = urb->context; 1490 struct ims_pcu *pcu = urb->context;
@@ -1624,7 +1853,6 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
1624 static atomic_t device_no = ATOMIC_INIT(0); 1853 static atomic_t device_no = ATOMIC_INIT(0);
1625 1854
1626 const struct ims_pcu_device_info *info; 1855 const struct ims_pcu_device_info *info;
1627 u8 device_id;
1628 int error; 1856 int error;
1629 1857
1630 error = ims_pcu_get_device_info(pcu); 1858 error = ims_pcu_get_device_info(pcu);
@@ -1633,7 +1861,7 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
1633 return error; 1861 return error;
1634 } 1862 }
1635 1863
1636 error = ims_pcu_identify_type(pcu, &device_id); 1864 error = ims_pcu_identify_type(pcu, &pcu->device_id);
1637 if (error) { 1865 if (error) {
1638 dev_err(pcu->dev, 1866 dev_err(pcu->dev,
1639 "Failed to identify device, error: %d\n", error); 1867 "Failed to identify device, error: %d\n", error);
@@ -1645,9 +1873,9 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
1645 return 0; 1873 return 0;
1646 } 1874 }
1647 1875
1648 if (device_id >= ARRAY_SIZE(ims_pcu_device_info) || 1876 if (pcu->device_id >= ARRAY_SIZE(ims_pcu_device_info) ||
1649 !ims_pcu_device_info[device_id].keymap) { 1877 !ims_pcu_device_info[pcu->device_id].keymap) {
1650 dev_err(pcu->dev, "Device ID %d is not valid\n", device_id); 1878 dev_err(pcu->dev, "Device ID %d is not valid\n", pcu->device_id);
1651 /* Same as above, punt to userspace */ 1879 /* Same as above, punt to userspace */
1652 return 0; 1880 return 0;
1653 } 1881 }
@@ -1655,11 +1883,21 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
1655 /* Device appears to be operable, complete initialization */ 1883 /* Device appears to be operable, complete initialization */
1656 pcu->device_no = atomic_inc_return(&device_no) - 1; 1884 pcu->device_no = atomic_inc_return(&device_no) - 1;
1657 1885
1886 /*
1887 * PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor
1888 */
1889 if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID) {
1890 error = sysfs_create_group(&pcu->dev->kobj,
1891 &ims_pcu_ofn_attr_group);
1892 if (error)
1893 return error;
1894 }
1895
1658 error = ims_pcu_setup_backlight(pcu); 1896 error = ims_pcu_setup_backlight(pcu);
1659 if (error) 1897 if (error)
1660 return error; 1898 return error;
1661 1899
1662 info = &ims_pcu_device_info[device_id]; 1900 info = &ims_pcu_device_info[pcu->device_id];
1663 error = ims_pcu_setup_buttons(pcu, info->keymap, info->keymap_len); 1901 error = ims_pcu_setup_buttons(pcu, info->keymap, info->keymap_len);
1664 if (error) 1902 if (error)
1665 goto err_destroy_backlight; 1903 goto err_destroy_backlight;
@@ -1691,6 +1929,10 @@ static void ims_pcu_destroy_application_mode(struct ims_pcu *pcu)
1691 ims_pcu_destroy_gamepad(pcu); 1929 ims_pcu_destroy_gamepad(pcu);
1692 ims_pcu_destroy_buttons(pcu); 1930 ims_pcu_destroy_buttons(pcu);
1693 ims_pcu_destroy_backlight(pcu); 1931 ims_pcu_destroy_backlight(pcu);
1932
1933 if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID)
1934 sysfs_remove_group(&pcu->dev->kobj,
1935 &ims_pcu_ofn_attr_group);
1694 } 1936 }
1695} 1937}
1696 1938