wm8775.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * wm8775 - driver version 0.0.1
  3. *
  4. * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
  5. *
  6. * Based on saa7115 driver
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. */
  22. #include <linux/module.h>
  23. #include <linux/types.h>
  24. #include <linux/ioctl.h>
  25. #include <asm/uaccess.h>
  26. #include <linux/i2c.h>
  27. #include <linux/videodev.h>
  28. #include <media/audiochip.h>
  29. #include <media/id.h>
  30. MODULE_DESCRIPTION("wm8775 driver");
  31. MODULE_AUTHOR("Ulf Eklund");
  32. MODULE_LICENSE("GPL");
  33. #define wm8775_err(fmt, arg...) do { \
  34. printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \
  35. i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
  36. #define wm8775_info(fmt, arg...) do { \
  37. printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \
  38. i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0)
  39. static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END };
  40. I2C_CLIENT_INSMOD;
  41. /* ----------------------------------------------------------------------- */
  42. enum {
  43. R7 = 7, R11 = 11,
  44. R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R23 = 23,
  45. TOT_REGS
  46. };
  47. struct wm8775_state {
  48. u8 input; /* Last selected input (0-0xf) */
  49. u8 muted;
  50. };
  51. static int wm8775_write(struct i2c_client *client, int reg, u16 val)
  52. {
  53. int i;
  54. if (reg < 0 || reg >= TOT_REGS) {
  55. wm8775_err("Invalid register R%d\n", reg);
  56. return -1;
  57. }
  58. for (i = 0; i < 3; i++) {
  59. if (i2c_smbus_write_byte_data(client, (reg << 1) |
  60. (val >> 8), val & 0xff) == 0) {
  61. return 0;
  62. }
  63. }
  64. wm8775_err("I2C: cannot write %03x to register R%d\n", val, reg);
  65. return -1;
  66. }
  67. static int wm8775_command(struct i2c_client *client, unsigned int cmd,
  68. void *arg)
  69. {
  70. struct wm8775_state *state = i2c_get_clientdata(client);
  71. int *input = arg;
  72. switch (cmd) {
  73. case AUDC_SET_INPUT:
  74. wm8775_write(client, R21, 0x0c0);
  75. wm8775_write(client, R14, 0x1d4);
  76. wm8775_write(client, R15, 0x1d4);
  77. if (*input == AUDIO_RADIO) {
  78. wm8775_write(client, R21, 0x108);
  79. state->input = 8;
  80. state->muted = 0;
  81. break;
  82. }
  83. if (*input == AUDIO_MUTE) {
  84. state->muted = 1;
  85. break;
  86. }
  87. if (*input == AUDIO_UNMUTE) {
  88. wm8775_write(client, R21, 0x100 + state->input);
  89. state->muted = 0;
  90. break;
  91. }
  92. /* All other inputs... */
  93. wm8775_write(client, R21, 0x102);
  94. state->input = 2;
  95. state->muted = 0;
  96. break;
  97. case VIDIOCSFREQ:
  98. /* If I remove this, then it can happen that I have no
  99. sound the first time I tune from static to a valid channel.
  100. It's difficult to reproduce and is almost certainly related
  101. to the zero cross detect circuit. */
  102. wm8775_write(client, R21, 0x0c0);
  103. wm8775_write(client, R14, 0x1d4);
  104. wm8775_write(client, R15, 0x1d4);
  105. wm8775_write(client, R21, 0x100 + state->input);
  106. break;
  107. default:
  108. return -EINVAL;
  109. }
  110. return 0;
  111. }
  112. /* ----------------------------------------------------------------------- */
  113. /* i2c implementation */
  114. /*
  115. * Generic i2c probe
  116. * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
  117. */
  118. static struct i2c_driver i2c_driver;
  119. static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind)
  120. {
  121. struct i2c_client *client;
  122. struct wm8775_state *state;
  123. /* Check if the adapter supports the needed features */
  124. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
  125. return 0;
  126. client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
  127. if (client == 0)
  128. return -ENOMEM;
  129. memset(client, 0, sizeof(struct i2c_client));
  130. client->addr = address;
  131. client->adapter = adapter;
  132. client->driver = &i2c_driver;
  133. client->flags = I2C_CLIENT_ALLOW_USE;
  134. snprintf(client->name, sizeof(client->name) - 1, "wm8775");
  135. wm8775_info("chip found @ 0x%x (%s)\n", address << 1, adapter->name);
  136. state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
  137. if (state == NULL) {
  138. kfree(client);
  139. return -ENOMEM;
  140. }
  141. state->input = 2;
  142. state->muted = 0;
  143. i2c_set_clientdata(client, state);
  144. /* initialize wm8775 */
  145. wm8775_write(client, R23, 0x000); /* RESET */
  146. wm8775_write(client, R7, 0x000); /* Disable zero cross detect timeout */
  147. wm8775_write(client, R11, 0x021); /* Left justified, 24-bit mode */
  148. wm8775_write(client, R12, 0x102); /* Master mode, clock ratio 256fs */
  149. wm8775_write(client, R13, 0x000); /* Powered up */
  150. wm8775_write(client, R14, 0x1d4); /* ADC gain +2.5dB, enable zero cross */
  151. wm8775_write(client, R15, 0x1d4); /* ADC gain +2.5dB, enable zero cross */
  152. wm8775_write(client, R16, 0x1bf); /* ALC Stereo, ALC target level -1dB FS */
  153. /* max gain +8dB */
  154. wm8775_write(client, R17, 0x185); /* Enable gain control, use zero cross */
  155. /* detection, ALC hold time 42.6 ms */
  156. wm8775_write(client, R18, 0x0a2); /* ALC gain ramp up delay 34 s, */
  157. /* ALC gain ramp down delay 33 ms */
  158. wm8775_write(client, R19, 0x005); /* Enable noise gate, threshold -72dBfs */
  159. wm8775_write(client, R20, 0x07a); /* Transient window 4ms, lower PGA gain */
  160. /* limit -1dB */
  161. wm8775_write(client, R21, 0x102); /* LRBOTH = 1, use input 2. */
  162. i2c_attach_client(client);
  163. return 0;
  164. }
  165. static int wm8775_probe(struct i2c_adapter *adapter)
  166. {
  167. #ifdef I2C_CLASS_TV_ANALOG
  168. if (adapter->class & I2C_CLASS_TV_ANALOG)
  169. return i2c_probe(adapter, &addr_data, wm8775_attach);
  170. #else
  171. switch (adapter->id) {
  172. case I2C_HW_B_BT848:
  173. return i2c_probe(adapter, &addr_data, tda9887_attach);
  174. }
  175. #endif /* I2C_CLASS_TV_ANALOG */
  176. return 0;
  177. }
  178. static int wm8775_detach(struct i2c_client *client)
  179. {
  180. int err;
  181. err = i2c_detach_client(client);
  182. if (err) {
  183. return err;
  184. }
  185. kfree(client);
  186. return 0;
  187. }
  188. /* ----------------------------------------------------------------------- */
  189. /* i2c implementation */
  190. static struct i2c_driver i2c_driver = {
  191. .name = "wm8775",
  192. .id = I2C_DRIVERID_WM8775,
  193. .flags = I2C_DF_NOTIFY,
  194. .attach_adapter = wm8775_probe,
  195. .detach_client = wm8775_detach,
  196. .command = wm8775_command,
  197. .owner = THIS_MODULE,
  198. };
  199. static int __init wm8775_init_module(void)
  200. {
  201. return i2c_add_driver(&i2c_driver);
  202. }
  203. static void __exit wm8775_cleanup_module(void)
  204. {
  205. i2c_del_driver(&i2c_driver);
  206. }
  207. module_init(wm8775_init_module);
  208. module_exit(wm8775_cleanup_module);