Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] m88ds3103: add I2C client binding

Implement I2C client device binding.
Wrap media attach to driver I2C probe.
Add wrapper from m88ds3103_attach() to m88ds3103_probe() via driver
core in order to provide proper I2C client for legacy media attach
binding.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>

authored by

Antti Palosaari and committed by
Mauro Carvalho Chehab
f01919e8 befa0cc1

+251 -94
+192 -88
drivers/media/dvb-frontends/m88ds3103.c
··· 1357 1357 static void m88ds3103_release(struct dvb_frontend *fe) 1358 1358 { 1359 1359 struct m88ds3103_priv *priv = fe->demodulator_priv; 1360 + struct i2c_client *client = priv->client; 1360 1361 1361 - i2c_del_mux_adapter(priv->i2c_adapter); 1362 - kfree(priv); 1362 + i2c_unregister_device(client); 1363 1363 } 1364 1364 1365 1365 static int m88ds3103_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) ··· 1401 1401 return 0; 1402 1402 } 1403 1403 1404 + /* 1405 + * XXX: That is wrapper to m88ds3103_probe() via driver core in order to provide 1406 + * proper I2C client for legacy media attach binding. 1407 + * New users must use I2C client binding directly! 1408 + */ 1404 1409 struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, 1405 1410 struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter) 1406 1411 { 1407 - int ret; 1408 - struct m88ds3103_priv *priv; 1409 - u8 chip_id, u8tmp; 1412 + struct i2c_client *client; 1413 + struct i2c_board_info board_info; 1414 + struct m88ds3103_platform_data pdata; 1410 1415 1411 - /* allocate memory for the internal priv */ 1412 - priv = kzalloc(sizeof(*priv), GFP_KERNEL); 1413 - if (!priv) { 1414 - ret = -ENOMEM; 1415 - dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); 1416 - goto err; 1417 - } 1416 + pdata.clk = cfg->clock; 1417 + pdata.i2c_wr_max = cfg->i2c_wr_max; 1418 + pdata.ts_mode = cfg->ts_mode; 1419 + pdata.ts_clk = cfg->ts_clk; 1420 + pdata.ts_clk_pol = cfg->ts_clk_pol; 1421 + pdata.spec_inv = cfg->spec_inv; 1422 + pdata.agc = cfg->agc; 1423 + pdata.agc_inv = cfg->agc_inv; 1424 + pdata.clk_out = cfg->clock_out; 1425 + pdata.envelope_mode = cfg->envelope_mode; 1426 + pdata.lnb_hv_pol = cfg->lnb_hv_pol; 1427 + pdata.lnb_en_pol = cfg->lnb_en_pol; 1428 + pdata.attach_in_use = true; 1418 1429 1419 - priv->cfg = cfg; 1420 - priv->i2c = i2c; 1421 - mutex_init(&priv->i2c_mutex); 1430 + memset(&board_info, 0, sizeof(board_info)); 1431 + strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); 1432 + board_info.addr = cfg->i2c_addr; 1433 + board_info.platform_data = &pdata; 1434 + client = i2c_new_device(i2c, &board_info); 1435 + if (!client || !client->dev.driver) 1436 + return NULL; 1422 1437 1423 - /* 0x00: chip id[6:0], 0x01: chip ver[7:0], 0x02: chip ver[15:8] */ 1424 - ret = m88ds3103_rd_reg(priv, 0x00, &chip_id); 1425 - if (ret) 1426 - goto err; 1427 - 1428 - chip_id >>= 1; 1429 - dev_info(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id); 1430 - 1431 - switch (chip_id) { 1432 - case M88RS6000_CHIP_ID: 1433 - case M88DS3103_CHIP_ID: 1434 - break; 1435 - default: 1436 - goto err; 1437 - } 1438 - priv->chip_id = chip_id; 1439 - 1440 - switch (priv->cfg->clock_out) { 1441 - case M88DS3103_CLOCK_OUT_DISABLED: 1442 - u8tmp = 0x80; 1443 - break; 1444 - case M88DS3103_CLOCK_OUT_ENABLED: 1445 - u8tmp = 0x00; 1446 - break; 1447 - case M88DS3103_CLOCK_OUT_ENABLED_DIV2: 1448 - u8tmp = 0x10; 1449 - break; 1450 - default: 1451 - goto err; 1452 - } 1453 - 1454 - /* 0x29 register is defined differently for m88rs6000. */ 1455 - /* set internal tuner address to 0x21 */ 1456 - if (chip_id == M88RS6000_CHIP_ID) 1457 - u8tmp = 0x00; 1458 - 1459 - ret = m88ds3103_wr_reg(priv, 0x29, u8tmp); 1460 - if (ret) 1461 - goto err; 1462 - 1463 - /* sleep */ 1464 - ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x00, 0x01); 1465 - if (ret) 1466 - goto err; 1467 - 1468 - ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x01, 0x01); 1469 - if (ret) 1470 - goto err; 1471 - 1472 - ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x10, 0x10); 1473 - if (ret) 1474 - goto err; 1475 - 1476 - /* create mux i2c adapter for tuner */ 1477 - priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0, 1478 - m88ds3103_select, m88ds3103_deselect); 1479 - if (priv->i2c_adapter == NULL) 1480 - goto err; 1481 - 1482 - *tuner_i2c_adapter = priv->i2c_adapter; 1483 - 1484 - /* create dvb_frontend */ 1485 - memcpy(&priv->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); 1486 - if (priv->chip_id == M88RS6000_CHIP_ID) 1487 - strncpy(priv->fe.ops.info.name, 1488 - "Montage M88RS6000", sizeof(priv->fe.ops.info.name)); 1489 - priv->fe.demodulator_priv = priv; 1490 - 1491 - return &priv->fe; 1492 - err: 1493 - dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret); 1494 - kfree(priv); 1495 - return NULL; 1438 + *tuner_i2c_adapter = pdata.get_i2c_adapter(client); 1439 + return pdata.get_dvb_frontend(client); 1496 1440 } 1497 1441 EXPORT_SYMBOL(m88ds3103_attach); 1498 1442 ··· 1484 1540 .set_tone = m88ds3103_set_tone, 1485 1541 .set_voltage = m88ds3103_set_voltage, 1486 1542 }; 1543 + 1544 + static struct dvb_frontend *m88ds3103_get_dvb_frontend(struct i2c_client *client) 1545 + { 1546 + struct m88ds3103_priv *dev = i2c_get_clientdata(client); 1547 + 1548 + dev_dbg(&client->dev, "\n"); 1549 + 1550 + return &dev->fe; 1551 + } 1552 + 1553 + static struct i2c_adapter *m88ds3103_get_i2c_adapter(struct i2c_client *client) 1554 + { 1555 + struct m88ds3103_priv *dev = i2c_get_clientdata(client); 1556 + 1557 + dev_dbg(&client->dev, "\n"); 1558 + 1559 + return dev->i2c_adapter; 1560 + } 1561 + 1562 + static int m88ds3103_probe(struct i2c_client *client, 1563 + const struct i2c_device_id *id) 1564 + { 1565 + struct m88ds3103_priv *dev; 1566 + struct m88ds3103_platform_data *pdata = client->dev.platform_data; 1567 + int ret; 1568 + u8 chip_id, u8tmp; 1569 + 1570 + dev = kzalloc(sizeof(*dev), GFP_KERNEL); 1571 + if (!dev) { 1572 + ret = -ENOMEM; 1573 + goto err; 1574 + } 1575 + 1576 + dev->client = client; 1577 + dev->i2c = client->adapter; 1578 + dev->config.i2c_addr = client->addr; 1579 + dev->config.clock = pdata->clk; 1580 + dev->config.i2c_wr_max = pdata->i2c_wr_max; 1581 + dev->config.ts_mode = pdata->ts_mode; 1582 + dev->config.ts_clk = pdata->ts_clk; 1583 + dev->config.ts_clk_pol = pdata->ts_clk_pol; 1584 + dev->config.spec_inv = pdata->spec_inv; 1585 + dev->config.agc_inv = pdata->agc_inv; 1586 + dev->config.clock_out = pdata->clk_out; 1587 + dev->config.envelope_mode = pdata->envelope_mode; 1588 + dev->config.agc = pdata->agc; 1589 + dev->config.lnb_hv_pol = pdata->lnb_hv_pol; 1590 + dev->config.lnb_en_pol = pdata->lnb_en_pol; 1591 + dev->cfg = &dev->config; 1592 + mutex_init(&dev->i2c_mutex); 1593 + 1594 + /* 0x00: chip id[6:0], 0x01: chip ver[7:0], 0x02: chip ver[15:8] */ 1595 + ret = m88ds3103_rd_reg(dev, 0x00, &chip_id); 1596 + if (ret) 1597 + goto err_kfree; 1598 + 1599 + chip_id >>= 1; 1600 + dev_dbg(&client->dev, "chip_id=%02x\n", chip_id); 1601 + 1602 + switch (chip_id) { 1603 + case M88RS6000_CHIP_ID: 1604 + case M88DS3103_CHIP_ID: 1605 + break; 1606 + default: 1607 + goto err_kfree; 1608 + } 1609 + dev->chip_id = chip_id; 1610 + 1611 + switch (dev->cfg->clock_out) { 1612 + case M88DS3103_CLOCK_OUT_DISABLED: 1613 + u8tmp = 0x80; 1614 + break; 1615 + case M88DS3103_CLOCK_OUT_ENABLED: 1616 + u8tmp = 0x00; 1617 + break; 1618 + case M88DS3103_CLOCK_OUT_ENABLED_DIV2: 1619 + u8tmp = 0x10; 1620 + break; 1621 + default: 1622 + goto err_kfree; 1623 + } 1624 + 1625 + /* 0x29 register is defined differently for m88rs6000. */ 1626 + /* set internal tuner address to 0x21 */ 1627 + if (chip_id == M88RS6000_CHIP_ID) 1628 + u8tmp = 0x00; 1629 + 1630 + ret = m88ds3103_wr_reg(dev, 0x29, u8tmp); 1631 + if (ret) 1632 + goto err_kfree; 1633 + 1634 + /* sleep */ 1635 + ret = m88ds3103_wr_reg_mask(dev, 0x08, 0x00, 0x01); 1636 + if (ret) 1637 + goto err_kfree; 1638 + ret = m88ds3103_wr_reg_mask(dev, 0x04, 0x01, 0x01); 1639 + if (ret) 1640 + goto err_kfree; 1641 + ret = m88ds3103_wr_reg_mask(dev, 0x23, 0x10, 0x10); 1642 + if (ret) 1643 + goto err_kfree; 1644 + 1645 + /* create mux i2c adapter for tuner */ 1646 + dev->i2c_adapter = i2c_add_mux_adapter(client->adapter, &client->dev, 1647 + dev, 0, 0, 0, m88ds3103_select, 1648 + m88ds3103_deselect); 1649 + if (dev->i2c_adapter == NULL) 1650 + goto err_kfree; 1651 + 1652 + /* create dvb_frontend */ 1653 + memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); 1654 + if (dev->chip_id == M88RS6000_CHIP_ID) 1655 + strncpy(dev->fe.ops.info.name, 1656 + "Montage M88RS6000", sizeof(dev->fe.ops.info.name)); 1657 + if (!pdata->attach_in_use) 1658 + dev->fe.ops.release = NULL; 1659 + dev->fe.demodulator_priv = dev; 1660 + i2c_set_clientdata(client, dev); 1661 + 1662 + /* setup callbacks */ 1663 + pdata->get_dvb_frontend = m88ds3103_get_dvb_frontend; 1664 + pdata->get_i2c_adapter = m88ds3103_get_i2c_adapter; 1665 + return 0; 1666 + err_kfree: 1667 + kfree(dev); 1668 + err: 1669 + dev_dbg(&client->dev, "failed=%d\n", ret); 1670 + return ret; 1671 + } 1672 + 1673 + static int m88ds3103_remove(struct i2c_client *client) 1674 + { 1675 + struct m88ds3103_priv *dev = i2c_get_clientdata(client); 1676 + 1677 + dev_dbg(&client->dev, "\n"); 1678 + 1679 + i2c_del_mux_adapter(dev->i2c_adapter); 1680 + 1681 + kfree(dev); 1682 + return 0; 1683 + } 1684 + 1685 + static const struct i2c_device_id m88ds3103_id_table[] = { 1686 + {"m88ds3103", 0}, 1687 + {} 1688 + }; 1689 + MODULE_DEVICE_TABLE(i2c, m88ds3103_id_table); 1690 + 1691 + static struct i2c_driver m88ds3103_driver = { 1692 + .driver = { 1693 + .owner = THIS_MODULE, 1694 + .name = "m88ds3103", 1695 + .suppress_bind_attrs = true, 1696 + }, 1697 + .probe = m88ds3103_probe, 1698 + .remove = m88ds3103_remove, 1699 + .id_table = m88ds3103_id_table, 1700 + }; 1701 + 1702 + module_i2c_driver(m88ds3103_driver); 1487 1703 1488 1704 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 1489 1705 MODULE_DESCRIPTION("Montage M88DS3103 DVB-S/S2 demodulator driver");
+57 -6
drivers/media/dvb-frontends/m88ds3103.h
··· 19 19 20 20 #include <linux/dvb/frontend.h> 21 21 22 + /* 23 + * I2C address 24 + * 0x68, 25 + */ 26 + 27 + /** 28 + * struct m88ds3103_platform_data - Platform data for the m88ds3103 driver 29 + * @clk: Clock frequency. 30 + * @i2c_wr_max: Max bytes I2C adapter can write at once. 31 + * @ts_mode: TS mode. 32 + * @ts_clk: TS clock (KHz). 33 + * @ts_clk_pol: TS clk polarity. 1-active at falling edge; 0-active at rising 34 + * edge. 35 + * @spec_inv: Input spectrum inversion. 36 + * @agc: AGC configuration. 37 + * @agc_inv: AGC polarity. 38 + * @clk_out: Clock output. 39 + * @envelope_mode: DiSEqC envelope mode. 40 + * @lnb_hv_pol: LNB H/V pin polarity. 0: pin high set to VOLTAGE_18, pin low to 41 + * set VOLTAGE_13. 1: pin high set to VOLTAGE_13, pin low to set VOLTAGE_18. 42 + * @lnb_en_pol: LNB enable pin polarity. 0: pin high to disable, pin low to 43 + * enable. 1: pin high to enable, pin low to disable. 44 + * @get_dvb_frontend: Get DVB frontend. 45 + * @get_i2c_adapter: Get I2C adapter. 46 + */ 47 + 48 + struct m88ds3103_platform_data { 49 + u32 clk; 50 + u16 i2c_wr_max; 51 + #define M88DS3103_TS_SERIAL 0 /* TS output pin D0, normal */ 52 + #define M88DS3103_TS_SERIAL_D7 1 /* TS output pin D7 */ 53 + #define M88DS3103_TS_PARALLEL 2 /* TS Parallel mode */ 54 + #define M88DS3103_TS_CI 3 /* TS CI Mode */ 55 + u8 ts_mode:2; 56 + u32 ts_clk; 57 + u8 ts_clk_pol:1; 58 + u8 spec_inv:1; 59 + u8 agc; 60 + u8 agc_inv:1; 61 + #define M88DS3103_CLOCK_OUT_DISABLED 0 62 + #define M88DS3103_CLOCK_OUT_ENABLED 1 63 + #define M88DS3103_CLOCK_OUT_ENABLED_DIV2 2 64 + u8 clk_out:2; 65 + u8 envelope_mode:1; 66 + u8 lnb_hv_pol:1; 67 + u8 lnb_en_pol:1; 68 + 69 + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); 70 + struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *); 71 + 72 + /* private: For legacy media attach wrapper. Do not set value. */ 73 + u8 attach_in_use:1; 74 + }; 75 + 76 + /* 77 + * Do not add new m88ds3103_attach() users! Use I2C bindings instead. 78 + */ 22 79 struct m88ds3103_config { 23 80 /* 24 81 * I2C address ··· 169 112 */ 170 113 u8 lnb_en_pol:1; 171 114 }; 172 - 173 - /* 174 - * Driver implements own I2C-adapter for tuner I2C access. That's since chip 175 - * has I2C-gate control which closes gate automatically after I2C transfer. 176 - * Using own I2C adapter we can workaround that. 177 - */ 178 115 179 116 #if defined(CONFIG_DVB_M88DS3103) || \ 180 117 (defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
+2
drivers/media/dvb-frontends/m88ds3103_priv.h
··· 32 32 33 33 struct m88ds3103_priv { 34 34 struct i2c_adapter *i2c; 35 + struct i2c_client *client; 35 36 /* mutex needed due to own tuner I2C adapter */ 36 37 struct mutex i2c_mutex; 38 + struct m88ds3103_config config; 37 39 const struct m88ds3103_config *cfg; 38 40 struct dvb_frontend fe; 39 41 fe_delivery_system_t delivery_system;