cs3308.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Cirrus Logic cs3308 8-Channel Analog Volume Control
  4. *
  5. * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
  6. * Copyright (C) 2012 Steven Toth <stoth@kernellabs.com>
  7. *
  8. * Derived from cs5345.c Copyright (C) 2007 Hans Verkuil
  9. */
  10. #include <linux/module.h>
  11. #include <linux/kernel.h>
  12. #include <linux/i2c.h>
  13. #include <linux/slab.h>
  14. #include <linux/videodev2.h>
  15. #include <media/v4l2-device.h>
  16. MODULE_DESCRIPTION("i2c device driver for cs3308 8-channel volume control");
  17. MODULE_AUTHOR("Devin Heitmueller");
  18. MODULE_LICENSE("GPL");
  19. static inline int cs3308_write(struct v4l2_subdev *sd, u8 reg, u8 value)
  20. {
  21. struct i2c_client *client = v4l2_get_subdevdata(sd);
  22. return i2c_smbus_write_byte_data(client, reg, value);
  23. }
  24. static inline int cs3308_read(struct v4l2_subdev *sd, u8 reg)
  25. {
  26. struct i2c_client *client = v4l2_get_subdevdata(sd);
  27. return i2c_smbus_read_byte_data(client, reg);
  28. }
  29. #ifdef CONFIG_VIDEO_ADV_DEBUG
  30. static int cs3308_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
  31. {
  32. reg->val = cs3308_read(sd, reg->reg & 0xffff);
  33. reg->size = 1;
  34. return 0;
  35. }
  36. static int cs3308_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
  37. {
  38. cs3308_write(sd, reg->reg & 0xffff, reg->val & 0xff);
  39. return 0;
  40. }
  41. #endif
  42. /* ----------------------------------------------------------------------- */
  43. static const struct v4l2_subdev_core_ops cs3308_core_ops = {
  44. #ifdef CONFIG_VIDEO_ADV_DEBUG
  45. .g_register = cs3308_g_register,
  46. .s_register = cs3308_s_register,
  47. #endif
  48. };
  49. static const struct v4l2_subdev_ops cs3308_ops = {
  50. .core = &cs3308_core_ops,
  51. };
  52. /* ----------------------------------------------------------------------- */
  53. static int cs3308_probe(struct i2c_client *client)
  54. {
  55. struct v4l2_subdev *sd;
  56. unsigned i;
  57. /* Check if the adapter supports the needed features */
  58. if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
  59. return -EIO;
  60. if ((i2c_smbus_read_byte_data(client, 0x1c) & 0xf0) != 0xe0)
  61. return -ENODEV;
  62. v4l_info(client, "chip found @ 0x%x (%s)\n",
  63. client->addr << 1, client->adapter->name);
  64. sd = kzalloc_obj(struct v4l2_subdev);
  65. if (sd == NULL)
  66. return -ENOMEM;
  67. v4l2_i2c_subdev_init(sd, client, &cs3308_ops);
  68. /* Set some reasonable defaults */
  69. cs3308_write(sd, 0x0d, 0x00); /* Power up all channels */
  70. cs3308_write(sd, 0x0e, 0x00); /* Master Power */
  71. cs3308_write(sd, 0x0b, 0x00); /* Device Configuration */
  72. /* Set volume for each channel */
  73. for (i = 1; i <= 8; i++)
  74. cs3308_write(sd, i, 0xd2);
  75. cs3308_write(sd, 0x0a, 0x00); /* Unmute all channels */
  76. return 0;
  77. }
  78. /* ----------------------------------------------------------------------- */
  79. static void cs3308_remove(struct i2c_client *client)
  80. {
  81. struct v4l2_subdev *sd = i2c_get_clientdata(client);
  82. v4l2_device_unregister_subdev(sd);
  83. kfree(sd);
  84. }
  85. /* ----------------------------------------------------------------------- */
  86. static const struct i2c_device_id cs3308_id[] = {
  87. { "cs3308" },
  88. { }
  89. };
  90. MODULE_DEVICE_TABLE(i2c, cs3308_id);
  91. static struct i2c_driver cs3308_driver = {
  92. .driver = {
  93. .name = "cs3308",
  94. },
  95. .probe = cs3308_probe,
  96. .remove = cs3308_remove,
  97. .id_table = cs3308_id,
  98. };
  99. module_i2c_driver(cs3308_driver);