aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2013-12-20 17:46:44 -0500
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-03-14 09:33:19 -0400
commitbce6744deb6dda6419f58eb90854d901bf937d44 (patch)
tree920aa974e03c54d33ac54942b54c7588905a3435 /drivers/media
parent814b4dd9aa4734f33ccf0e13d872391eaaa72762 (diff)
[media] V4L: s5c73m3: Add device tree support
This patch adds the V4L2 asynchronous subdev registration and device tree support. Common clock API is used to control the sensor master clock from within the subdev. Signed-off-by: Andrzej Hajda <a.hajda@samsung.com> Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c207
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-spi.c6
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3.h4
3 files changed, 167 insertions, 50 deletions
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index e7f555cc827a..a4459301b5f8 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -15,7 +15,7 @@
15 * GNU General Public License for more details. 15 * GNU General Public License for more details.
16 */ 16 */
17 17
18#include <linux/sizes.h> 18#include <linux/clk.h>
19#include <linux/delay.h> 19#include <linux/delay.h>
20#include <linux/firmware.h> 20#include <linux/firmware.h>
21#include <linux/gpio.h> 21#include <linux/gpio.h>
@@ -23,7 +23,9 @@
23#include <linux/init.h> 23#include <linux/init.h>
24#include <linux/media.h> 24#include <linux/media.h>
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/of_gpio.h>
26#include <linux/regulator/consumer.h> 27#include <linux/regulator/consumer.h>
28#include <linux/sizes.h>
27#include <linux/slab.h> 29#include <linux/slab.h>
28#include <linux/spi/spi.h> 30#include <linux/spi/spi.h>
29#include <linux/videodev2.h> 31#include <linux/videodev2.h>
@@ -33,6 +35,7 @@
33#include <media/v4l2-subdev.h> 35#include <media/v4l2-subdev.h>
34#include <media/v4l2-mediabus.h> 36#include <media/v4l2-mediabus.h>
35#include <media/s5c73m3.h> 37#include <media/s5c73m3.h>
38#include <media/v4l2-of.h>
36 39
37#include "s5c73m3.h" 40#include "s5c73m3.h"
38 41
@@ -46,6 +49,8 @@ static int update_fw;
46module_param(update_fw, int, 0644); 49module_param(update_fw, int, 0644);
47 50
48#define S5C73M3_EMBEDDED_DATA_MAXLEN SZ_4K 51#define S5C73M3_EMBEDDED_DATA_MAXLEN SZ_4K
52#define S5C73M3_MIPI_DATA_LANES 4
53#define S5C73M3_CLK_NAME "cis_extclk"
49 54
50static const char * const s5c73m3_supply_names[S5C73M3_MAX_SUPPLIES] = { 55static const char * const s5c73m3_supply_names[S5C73M3_MAX_SUPPLIES] = {
51 "vdd-int", /* Digital Core supply (1.2V), CAM_ISP_CORE_1.2V */ 56 "vdd-int", /* Digital Core supply (1.2V), CAM_ISP_CORE_1.2V */
@@ -1355,9 +1360,20 @@ static int __s5c73m3_power_on(struct s5c73m3 *state)
1355 for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) { 1360 for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) {
1356 ret = regulator_enable(state->supplies[i].consumer); 1361 ret = regulator_enable(state->supplies[i].consumer);
1357 if (ret) 1362 if (ret)
1358 goto err; 1363 goto err_reg_dis;
1359 } 1364 }
1360 1365
1366 ret = clk_set_rate(state->clock, state->mclk_frequency);
1367 if (ret < 0)
1368 goto err_reg_dis;
1369
1370 ret = clk_prepare_enable(state->clock);
1371 if (ret < 0)
1372 goto err_reg_dis;
1373
1374 v4l2_dbg(1, s5c73m3_dbg, &state->oif_sd, "clock frequency: %ld\n",
1375 clk_get_rate(state->clock));
1376
1361 s5c73m3_gpio_deassert(state, STBY); 1377 s5c73m3_gpio_deassert(state, STBY);
1362 usleep_range(100, 200); 1378 usleep_range(100, 200);
1363 1379
@@ -1365,7 +1381,8 @@ static int __s5c73m3_power_on(struct s5c73m3 *state)
1365 usleep_range(50, 100); 1381 usleep_range(50, 100);
1366 1382
1367 return 0; 1383 return 0;
1368err: 1384
1385err_reg_dis:
1369 for (--i; i >= 0; i--) 1386 for (--i; i >= 0; i--)
1370 regulator_disable(state->supplies[i].consumer); 1387 regulator_disable(state->supplies[i].consumer);
1371 return ret; 1388 return ret;
@@ -1380,6 +1397,9 @@ static int __s5c73m3_power_off(struct s5c73m3 *state)
1380 1397
1381 if (s5c73m3_gpio_assert(state, STBY)) 1398 if (s5c73m3_gpio_assert(state, STBY))
1382 usleep_range(100, 200); 1399 usleep_range(100, 200);
1400
1401 clk_disable_unprepare(state->clock);
1402
1383 state->streaming = 0; 1403 state->streaming = 0;
1384 state->isp_ready = 0; 1404 state->isp_ready = 0;
1385 1405
@@ -1388,6 +1408,7 @@ static int __s5c73m3_power_off(struct s5c73m3 *state)
1388 if (ret) 1408 if (ret)
1389 goto err; 1409 goto err;
1390 } 1410 }
1411
1391 return 0; 1412 return 0;
1392err: 1413err:
1393 for (++i; i < S5C73M3_MAX_SUPPLIES; i++) { 1414 for (++i; i < S5C73M3_MAX_SUPPLIES; i++) {
@@ -1396,6 +1417,8 @@ err:
1396 v4l2_err(&state->oif_sd, "Failed to reenable %s: %d\n", 1417 v4l2_err(&state->oif_sd, "Failed to reenable %s: %d\n",
1397 state->supplies[i].supply, r); 1418 state->supplies[i].supply, r);
1398 } 1419 }
1420
1421 clk_prepare_enable(state->clock);
1399 return ret; 1422 return ret;
1400} 1423}
1401 1424
@@ -1451,17 +1474,6 @@ static int s5c73m3_oif_registered(struct v4l2_subdev *sd)
1451 S5C73M3_JPEG_PAD, &state->oif_sd.entity, OIF_JPEG_PAD, 1474 S5C73M3_JPEG_PAD, &state->oif_sd.entity, OIF_JPEG_PAD,
1452 MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); 1475 MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
1453 1476
1454 mutex_lock(&state->lock);
1455 ret = __s5c73m3_power_on(state);
1456 if (ret == 0)
1457 s5c73m3_get_fw_version(state);
1458
1459 __s5c73m3_power_off(state);
1460 mutex_unlock(&state->lock);
1461
1462 v4l2_dbg(1, s5c73m3_dbg, sd, "%s: Booting %s (%d)\n",
1463 __func__, ret ? "failed" : "succeeded", ret);
1464
1465 return ret; 1477 return ret;
1466} 1478}
1467 1479
@@ -1519,41 +1531,112 @@ static const struct v4l2_subdev_ops oif_subdev_ops = {
1519 .video = &s5c73m3_oif_video_ops, 1531 .video = &s5c73m3_oif_video_ops,
1520}; 1532};
1521 1533
1522static int s5c73m3_configure_gpios(struct s5c73m3 *state, 1534static int s5c73m3_configure_gpios(struct s5c73m3 *state)
1523 const struct s5c73m3_platform_data *pdata) 1535{
1536 static const char * const gpio_names[] = {
1537 "S5C73M3_STBY", "S5C73M3_RST"
1538 };
1539 struct i2c_client *c = state->i2c_client;
1540 struct s5c73m3_gpio *g = state->gpio;
1541 int ret, i;
1542
1543 for (i = 0; i < GPIO_NUM; ++i) {
1544 unsigned int flags = GPIOF_DIR_OUT;
1545 if (g[i].level)
1546 flags |= GPIOF_INIT_HIGH;
1547 ret = devm_gpio_request_one(&c->dev, g[i].gpio, flags,
1548 gpio_names[i]);
1549 if (ret) {
1550 v4l2_err(c, "failed to request gpio %s\n",
1551 gpio_names[i]);
1552 return ret;
1553 }
1554 }
1555 return 0;
1556}
1557
1558static int s5c73m3_parse_gpios(struct s5c73m3 *state)
1559{
1560 static const char * const prop_names[] = {
1561 "standby-gpios", "xshutdown-gpios",
1562 };
1563 struct device *dev = &state->i2c_client->dev;
1564 struct device_node *node = dev->of_node;
1565 int ret, i;
1566
1567 for (i = 0; i < GPIO_NUM; ++i) {
1568 enum of_gpio_flags of_flags;
1569
1570 ret = of_get_named_gpio_flags(node, prop_names[i],
1571 0, &of_flags);
1572 if (ret < 0) {
1573 dev_err(dev, "failed to parse %s DT property\n",
1574 prop_names[i]);
1575 return -EINVAL;
1576 }
1577 state->gpio[i].gpio = ret;
1578 state->gpio[i].level = !(of_flags & OF_GPIO_ACTIVE_LOW);
1579 }
1580 return 0;
1581}
1582
1583static int s5c73m3_get_platform_data(struct s5c73m3 *state)
1524{ 1584{
1525 struct device *dev = &state->i2c_client->dev; 1585 struct device *dev = &state->i2c_client->dev;
1526 const struct s5c73m3_gpio *gpio; 1586 const struct s5c73m3_platform_data *pdata = dev->platform_data;
1527 unsigned long flags; 1587 struct device_node *node = dev->of_node;
1588 struct device_node *node_ep;
1589 struct v4l2_of_endpoint ep;
1528 int ret; 1590 int ret;
1529 1591
1530 state->gpio[STBY].gpio = -EINVAL; 1592 if (!node) {
1531 state->gpio[RST].gpio = -EINVAL; 1593 if (!pdata) {
1594 dev_err(dev, "Platform data not specified\n");
1595 return -EINVAL;
1596 }
1532 1597
1533 gpio = &pdata->gpio_stby; 1598 state->mclk_frequency = pdata->mclk_frequency;
1534 if (gpio_is_valid(gpio->gpio)) { 1599 state->gpio[STBY] = pdata->gpio_stby;
1535 flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW) 1600 state->gpio[RST] = pdata->gpio_reset;
1536 | GPIOF_EXPORT; 1601 return 0;
1537 ret = devm_gpio_request_one(dev, gpio->gpio, flags, 1602 }
1538 "S5C73M3_STBY"); 1603
1539 if (ret < 0) 1604 state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME);
1540 return ret; 1605 if (IS_ERR(state->clock))
1606 return PTR_ERR(state->clock);
1541 1607
1542 state->gpio[STBY] = *gpio; 1608 if (of_property_read_u32(node, "clock-frequency",
1609 &state->mclk_frequency)) {
1610 state->mclk_frequency = S5C73M3_DEFAULT_MCLK_FREQ;
1611 dev_info(dev, "using default %u Hz clock frequency\n",
1612 state->mclk_frequency);
1543 } 1613 }
1544 1614
1545 gpio = &pdata->gpio_reset; 1615 ret = s5c73m3_parse_gpios(state);
1546 if (gpio_is_valid(gpio->gpio)) { 1616 if (ret < 0)
1547 flags = (gpio->level ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW) 1617 return -EINVAL;
1548 | GPIOF_EXPORT;
1549 ret = devm_gpio_request_one(dev, gpio->gpio, flags,
1550 "S5C73M3_RST");
1551 if (ret < 0)
1552 return ret;
1553 1618
1554 state->gpio[RST] = *gpio; 1619 node_ep = v4l2_of_get_next_endpoint(node, NULL);
1620 if (!node_ep) {
1621 dev_warn(dev, "no endpoint defined for node: %s\n",
1622 node->full_name);
1623 return 0;
1555 } 1624 }
1556 1625
1626 v4l2_of_parse_endpoint(node_ep, &ep);
1627 of_node_put(node_ep);
1628
1629 if (ep.bus_type != V4L2_MBUS_CSI2) {
1630 dev_err(dev, "unsupported bus type\n");
1631 return -EINVAL;
1632 }
1633 /*
1634 * Number of MIPI CSI-2 data lanes is currently not configurable,
1635 * always a default value of 4 lanes is used.
1636 */
1637 if (ep.bus.mipi_csi2.num_data_lanes != S5C73M3_MIPI_DATA_LANES)
1638 dev_info(dev, "falling back to 4 MIPI CSI-2 data lanes\n");
1639
1557 return 0; 1640 return 0;
1558} 1641}
1559 1642
@@ -1561,21 +1644,20 @@ static int s5c73m3_probe(struct i2c_client *client,
1561 const struct i2c_device_id *id) 1644 const struct i2c_device_id *id)
1562{ 1645{
1563 struct device *dev = &client->dev; 1646 struct device *dev = &client->dev;
1564 const struct s5c73m3_platform_data *pdata = client->dev.platform_data;
1565 struct v4l2_subdev *sd; 1647 struct v4l2_subdev *sd;
1566 struct v4l2_subdev *oif_sd; 1648 struct v4l2_subdev *oif_sd;
1567 struct s5c73m3 *state; 1649 struct s5c73m3 *state;
1568 int ret, i; 1650 int ret, i;
1569 1651
1570 if (pdata == NULL) {
1571 dev_err(&client->dev, "Platform data not specified\n");
1572 return -EINVAL;
1573 }
1574
1575 state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); 1652 state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
1576 if (!state) 1653 if (!state)
1577 return -ENOMEM; 1654 return -ENOMEM;
1578 1655
1656 state->i2c_client = client;
1657 ret = s5c73m3_get_platform_data(state);
1658 if (ret < 0)
1659 return ret;
1660
1579 mutex_init(&state->lock); 1661 mutex_init(&state->lock);
1580 sd = &state->sensor_sd; 1662 sd = &state->sensor_sd;
1581 oif_sd = &state->oif_sd; 1663 oif_sd = &state->oif_sd;
@@ -1613,11 +1695,7 @@ static int s5c73m3_probe(struct i2c_client *client,
1613 if (ret < 0) 1695 if (ret < 0)
1614 return ret; 1696 return ret;
1615 1697
1616 state->mclk_frequency = pdata->mclk_frequency; 1698 ret = s5c73m3_configure_gpios(state);
1617 state->bus_type = pdata->bus_type;
1618 state->i2c_client = client;
1619
1620 ret = s5c73m3_configure_gpios(state, pdata);
1621 if (ret) 1699 if (ret)
1622 goto out_err; 1700 goto out_err;
1623 1701
@@ -1651,9 +1729,29 @@ static int s5c73m3_probe(struct i2c_client *client,
1651 if (ret < 0) 1729 if (ret < 0)
1652 goto out_err; 1730 goto out_err;
1653 1731
1732 oif_sd->dev = dev;
1733
1734 ret = __s5c73m3_power_on(state);
1735 if (ret < 0)
1736 goto out_err1;
1737
1738 ret = s5c73m3_get_fw_version(state);
1739 __s5c73m3_power_off(state);
1740
1741 if (ret < 0) {
1742 dev_err(dev, "Device detection failed: %d\n", ret);
1743 goto out_err1;
1744 }
1745
1746 ret = v4l2_async_register_subdev(oif_sd);
1747 if (ret < 0)
1748 goto out_err1;
1749
1654 v4l2_info(sd, "%s: completed successfully\n", __func__); 1750 v4l2_info(sd, "%s: completed successfully\n", __func__);
1655 return 0; 1751 return 0;
1656 1752
1753out_err1:
1754 s5c73m3_unregister_spi_driver(state);
1657out_err: 1755out_err:
1658 media_entity_cleanup(&sd->entity); 1756 media_entity_cleanup(&sd->entity);
1659 return ret; 1757 return ret;
@@ -1665,7 +1763,7 @@ static int s5c73m3_remove(struct i2c_client *client)
1665 struct s5c73m3 *state = oif_sd_to_s5c73m3(oif_sd); 1763 struct s5c73m3 *state = oif_sd_to_s5c73m3(oif_sd);
1666 struct v4l2_subdev *sensor_sd = &state->sensor_sd; 1764 struct v4l2_subdev *sensor_sd = &state->sensor_sd;
1667 1765
1668 v4l2_device_unregister_subdev(oif_sd); 1766 v4l2_async_unregister_subdev(oif_sd);
1669 1767
1670 v4l2_ctrl_handler_free(oif_sd->ctrl_handler); 1768 v4l2_ctrl_handler_free(oif_sd->ctrl_handler);
1671 media_entity_cleanup(&oif_sd->entity); 1769 media_entity_cleanup(&oif_sd->entity);
@@ -1684,8 +1782,17 @@ static const struct i2c_device_id s5c73m3_id[] = {
1684}; 1782};
1685MODULE_DEVICE_TABLE(i2c, s5c73m3_id); 1783MODULE_DEVICE_TABLE(i2c, s5c73m3_id);
1686 1784
1785#ifdef CONFIG_OF
1786static const struct of_device_id s5c73m3_of_match[] = {
1787 { .compatible = "samsung,s5c73m3" },
1788 { }
1789};
1790MODULE_DEVICE_TABLE(of, s5c73m3_of_match);
1791#endif
1792
1687static struct i2c_driver s5c73m3_i2c_driver = { 1793static struct i2c_driver s5c73m3_i2c_driver = {
1688 .driver = { 1794 .driver = {
1795 .of_match_table = of_match_ptr(s5c73m3_of_match),
1689 .name = DRIVER_NAME, 1796 .name = DRIVER_NAME,
1690 }, 1797 },
1691 .probe = s5c73m3_probe, 1798 .probe = s5c73m3_probe,
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
index 8079e26eb5e2..f60b265b4da1 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
@@ -27,6 +27,11 @@
27 27
28#define S5C73M3_SPI_DRV_NAME "S5C73M3-SPI" 28#define S5C73M3_SPI_DRV_NAME "S5C73M3-SPI"
29 29
30static const struct of_device_id s5c73m3_spi_ids[] = {
31 { .compatible = "samsung,s5c73m3" },
32 { }
33};
34
30enum spi_direction { 35enum spi_direction {
31 SPI_DIR_RX, 36 SPI_DIR_RX,
32 SPI_DIR_TX 37 SPI_DIR_TX
@@ -146,6 +151,7 @@ int s5c73m3_register_spi_driver(struct s5c73m3 *state)
146 spidrv->driver.name = S5C73M3_SPI_DRV_NAME; 151 spidrv->driver.name = S5C73M3_SPI_DRV_NAME;
147 spidrv->driver.bus = &spi_bus_type; 152 spidrv->driver.bus = &spi_bus_type;
148 spidrv->driver.owner = THIS_MODULE; 153 spidrv->driver.owner = THIS_MODULE;
154 spidrv->driver.of_match_table = s5c73m3_spi_ids;
149 155
150 return spi_register_driver(spidrv); 156 return spi_register_driver(spidrv);
151} 157}
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h
index 9dfa516f6944..9656b6723dc6 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3.h
+++ b/drivers/media/i2c/s5c73m3/s5c73m3.h
@@ -17,6 +17,7 @@
17#ifndef S5C73M3_H_ 17#ifndef S5C73M3_H_
18#define S5C73M3_H_ 18#define S5C73M3_H_
19 19
20#include <linux/clk.h>
20#include <linux/kernel.h> 21#include <linux/kernel.h>
21#include <linux/regulator/consumer.h> 22#include <linux/regulator/consumer.h>
22#include <media/v4l2-common.h> 23#include <media/v4l2-common.h>
@@ -321,6 +322,7 @@ enum s5c73m3_oif_pads {
321 322
322 323
323#define S5C73M3_MAX_SUPPLIES 6 324#define S5C73M3_MAX_SUPPLIES 6
325#define S5C73M3_DEFAULT_MCLK_FREQ 24000000U
324 326
325struct s5c73m3_ctrls { 327struct s5c73m3_ctrls {
326 struct v4l2_ctrl_handler handler; 328 struct v4l2_ctrl_handler handler;
@@ -391,6 +393,8 @@ struct s5c73m3 {
391 struct regulator_bulk_data supplies[S5C73M3_MAX_SUPPLIES]; 393 struct regulator_bulk_data supplies[S5C73M3_MAX_SUPPLIES];
392 struct s5c73m3_gpio gpio[GPIO_NUM]; 394 struct s5c73m3_gpio gpio[GPIO_NUM];
393 395
396 struct clk *clock;
397
394 /* External master clock frequency */ 398 /* External master clock frequency */
395 u32 mclk_frequency; 399 u32 mclk_frequency;
396 /* Video bus type - MIPI-CSI2/parallel */ 400 /* Video bus type - MIPI-CSI2/parallel */