Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * wm8739
0004  *
0005  * Copyright (C) 2005 T. Adachi <tadachi@tadachi-net.com>
0006  *
0007  * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
0008  * - Cleanup
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/types.h>
0013 #include <linux/slab.h>
0014 #include <linux/ioctl.h>
0015 #include <linux/uaccess.h>
0016 #include <linux/i2c.h>
0017 #include <linux/videodev2.h>
0018 #include <media/v4l2-device.h>
0019 #include <media/v4l2-ctrls.h>
0020 
0021 MODULE_DESCRIPTION("wm8739 driver");
0022 MODULE_AUTHOR("T. Adachi, Hans Verkuil");
0023 MODULE_LICENSE("GPL");
0024 
0025 static int debug;
0026 
0027 module_param(debug, int, 0644);
0028 
0029 MODULE_PARM_DESC(debug, "Debug level (0-1)");
0030 
0031 
0032 /* ------------------------------------------------------------------------ */
0033 
0034 enum {
0035     R0 = 0, R1,
0036     R5 = 5, R6, R7, R8, R9, R15 = 15,
0037     TOT_REGS
0038 };
0039 
0040 struct wm8739_state {
0041     struct v4l2_subdev sd;
0042     struct v4l2_ctrl_handler hdl;
0043     struct {
0044         /* audio cluster */
0045         struct v4l2_ctrl *volume;
0046         struct v4l2_ctrl *mute;
0047         struct v4l2_ctrl *balance;
0048     };
0049     u32 clock_freq;
0050 };
0051 
0052 static inline struct wm8739_state *to_state(struct v4l2_subdev *sd)
0053 {
0054     return container_of(sd, struct wm8739_state, sd);
0055 }
0056 
0057 static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
0058 {
0059     return &container_of(ctrl->handler, struct wm8739_state, hdl)->sd;
0060 }
0061 
0062 /* ------------------------------------------------------------------------ */
0063 
0064 static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val)
0065 {
0066     struct i2c_client *client = v4l2_get_subdevdata(sd);
0067     int i;
0068 
0069     if (reg < 0 || reg >= TOT_REGS) {
0070         v4l2_err(sd, "Invalid register R%d\n", reg);
0071         return -1;
0072     }
0073 
0074     v4l2_dbg(1, debug, sd, "write: %02x %02x\n", reg, val);
0075 
0076     for (i = 0; i < 3; i++)
0077         if (i2c_smbus_write_byte_data(client,
0078                 (reg << 1) | (val >> 8), val & 0xff) == 0)
0079             return 0;
0080     v4l2_err(sd, "I2C: cannot write %03x to register R%d\n", val, reg);
0081     return -1;
0082 }
0083 
0084 static int wm8739_s_ctrl(struct v4l2_ctrl *ctrl)
0085 {
0086     struct v4l2_subdev *sd = to_sd(ctrl);
0087     struct wm8739_state *state = to_state(sd);
0088     unsigned int work_l, work_r;
0089     u8 vol_l;   /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
0090     u8 vol_r;   /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
0091     u16 mute;
0092 
0093     switch (ctrl->id) {
0094     case V4L2_CID_AUDIO_VOLUME:
0095         break;
0096 
0097     default:
0098         return -EINVAL;
0099     }
0100 
0101     /* normalize ( 65535 to 0 -> 31 to 0 (12dB to -34.5dB) ) */
0102     work_l = (min(65536 - state->balance->val, 32768) * state->volume->val) / 32768;
0103     work_r = (min(state->balance->val, 32768) * state->volume->val) / 32768;
0104 
0105     vol_l = (long)work_l * 31 / 65535;
0106     vol_r = (long)work_r * 31 / 65535;
0107 
0108     /* set audio volume etc. */
0109     mute = state->mute->val ? 0x80 : 0;
0110 
0111     /* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB
0112      * Default setting: 0x17 = 0 dB
0113      */
0114     wm8739_write(sd, R0, (vol_l & 0x1f) | mute);
0115     wm8739_write(sd, R1, (vol_r & 0x1f) | mute);
0116     return 0;
0117 }
0118 
0119 /* ------------------------------------------------------------------------ */
0120 
0121 static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
0122 {
0123     struct wm8739_state *state = to_state(sd);
0124 
0125     state->clock_freq = audiofreq;
0126     /* de-activate */
0127     wm8739_write(sd, R9, 0x000);
0128     switch (audiofreq) {
0129     case 44100:
0130         /* 256fps, fs=44.1k */
0131         wm8739_write(sd, R8, 0x020);
0132         break;
0133     case 48000:
0134         /* 256fps, fs=48k */
0135         wm8739_write(sd, R8, 0x000);
0136         break;
0137     case 32000:
0138         /* 256fps, fs=32k */
0139         wm8739_write(sd, R8, 0x018);
0140         break;
0141     default:
0142         break;
0143     }
0144     /* activate */
0145     wm8739_write(sd, R9, 0x001);
0146     return 0;
0147 }
0148 
0149 static int wm8739_log_status(struct v4l2_subdev *sd)
0150 {
0151     struct wm8739_state *state = to_state(sd);
0152 
0153     v4l2_info(sd, "Frequency: %u Hz\n", state->clock_freq);
0154     v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
0155     return 0;
0156 }
0157 
0158 /* ----------------------------------------------------------------------- */
0159 
0160 static const struct v4l2_ctrl_ops wm8739_ctrl_ops = {
0161     .s_ctrl = wm8739_s_ctrl,
0162 };
0163 
0164 static const struct v4l2_subdev_core_ops wm8739_core_ops = {
0165     .log_status = wm8739_log_status,
0166 };
0167 
0168 static const struct v4l2_subdev_audio_ops wm8739_audio_ops = {
0169     .s_clock_freq = wm8739_s_clock_freq,
0170 };
0171 
0172 static const struct v4l2_subdev_ops wm8739_ops = {
0173     .core = &wm8739_core_ops,
0174     .audio = &wm8739_audio_ops,
0175 };
0176 
0177 /* ------------------------------------------------------------------------ */
0178 
0179 /* i2c implementation */
0180 
0181 static int wm8739_probe(struct i2c_client *client,
0182             const struct i2c_device_id *id)
0183 {
0184     struct wm8739_state *state;
0185     struct v4l2_subdev *sd;
0186 
0187     /* Check if the adapter supports the needed features */
0188     if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
0189         return -EIO;
0190 
0191     v4l_info(client, "chip found @ 0x%x (%s)\n",
0192             client->addr << 1, client->adapter->name);
0193 
0194     state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
0195     if (state == NULL)
0196         return -ENOMEM;
0197     sd = &state->sd;
0198     v4l2_i2c_subdev_init(sd, client, &wm8739_ops);
0199     v4l2_ctrl_handler_init(&state->hdl, 2);
0200     state->volume = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
0201             V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 50736);
0202     state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
0203             V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
0204     state->balance = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
0205             V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
0206     sd->ctrl_handler = &state->hdl;
0207     if (state->hdl.error) {
0208         int err = state->hdl.error;
0209 
0210         v4l2_ctrl_handler_free(&state->hdl);
0211         return err;
0212     }
0213     v4l2_ctrl_cluster(3, &state->volume);
0214 
0215     state->clock_freq = 48000;
0216 
0217     /* Initialize wm8739 */
0218 
0219     /* reset */
0220     wm8739_write(sd, R15, 0x00);
0221     /* filter setting, high path, offet clear */
0222     wm8739_write(sd, R5, 0x000);
0223     /* ADC, OSC, Power Off mode Disable */
0224     wm8739_write(sd, R6, 0x000);
0225     /* Digital Audio interface format:
0226        Enable Master mode, 24 bit, MSB first/left justified */
0227     wm8739_write(sd, R7, 0x049);
0228     /* sampling control: normal, 256fs, 48KHz sampling rate */
0229     wm8739_write(sd, R8, 0x000);
0230     /* activate */
0231     wm8739_write(sd, R9, 0x001);
0232     /* set volume/mute */
0233     v4l2_ctrl_handler_setup(&state->hdl);
0234     return 0;
0235 }
0236 
0237 static int wm8739_remove(struct i2c_client *client)
0238 {
0239     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0240     struct wm8739_state *state = to_state(sd);
0241 
0242     v4l2_device_unregister_subdev(sd);
0243     v4l2_ctrl_handler_free(&state->hdl);
0244     return 0;
0245 }
0246 
0247 static const struct i2c_device_id wm8739_id[] = {
0248     { "wm8739", 0 },
0249     { }
0250 };
0251 MODULE_DEVICE_TABLE(i2c, wm8739_id);
0252 
0253 static struct i2c_driver wm8739_driver = {
0254     .driver = {
0255         .name   = "wm8739",
0256     },
0257     .probe      = wm8739_probe,
0258     .remove     = wm8739_remove,
0259     .id_table   = wm8739_id,
0260 };
0261 
0262 module_i2c_driver(wm8739_driver);