18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * For the STS-Thompson TDA7432 audio processor chip 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Handles audio functions: volume, balance, tone, loudness 68c2ecf20Sopenharmony_ci * This driver will not complain if used with any 78c2ecf20Sopenharmony_ci * other i2c device with the same address. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Muting and tone control by Jonathan Isom <jisom@ematic.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com> 128c2ecf20Sopenharmony_ci * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) 158c2ecf20Sopenharmony_ci * Which was based on tda8425.c by Greg Alexander (c) 1998 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * OPTIONS: 188c2ecf20Sopenharmony_ci * debug - set to 1 if you'd like to see debug messages 198c2ecf20Sopenharmony_ci * set to 2 if you'd like to be inundated with debug messages 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * loudness - set between 0 and 15 for varying degrees of loudness effect 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * maxvol - set maximum volume to +20db (1), default is 0db(0) 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/module.h> 278c2ecf20Sopenharmony_ci#include <linux/init.h> 288c2ecf20Sopenharmony_ci#include <linux/kernel.h> 298c2ecf20Sopenharmony_ci#include <linux/string.h> 308c2ecf20Sopenharmony_ci#include <linux/timer.h> 318c2ecf20Sopenharmony_ci#include <linux/delay.h> 328c2ecf20Sopenharmony_ci#include <linux/errno.h> 338c2ecf20Sopenharmony_ci#include <linux/slab.h> 348c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 358c2ecf20Sopenharmony_ci#include <linux/i2c.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 388c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 398c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#ifndef VIDEO_AUDIO_BALANCE 428c2ecf20Sopenharmony_ci# define VIDEO_AUDIO_BALANCE 32 438c2ecf20Sopenharmony_ci#endif 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eric Sandeen <eric_sandeen@bigfoot.com>"); 468c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("bttv driver for the tda7432 audio processor chip"); 478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int maxvol; 508c2ecf20Sopenharmony_cistatic int loudness; /* disable loudness by default */ 518c2ecf20Sopenharmony_cistatic int debug; /* insmod parameter */ 528c2ecf20Sopenharmony_cimodule_param(debug, int, S_IRUGO | S_IWUSR); 538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Set debugging level from 0 to 3. Default is off(0)."); 548c2ecf20Sopenharmony_cimodule_param(loudness, int, S_IRUGO); 558c2ecf20Sopenharmony_ciMODULE_PARM_DESC(loudness, "Turn loudness on(1) else off(0). Default is off(0)."); 568c2ecf20Sopenharmony_cimodule_param(maxvol, int, S_IRUGO | S_IWUSR); 578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(maxvol, "Set maximum volume to +20dB(0) else +0dB(1). Default is +20dB(0)."); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* Structure of address and subaddresses for the tda7432 */ 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistruct tda7432 { 638c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 648c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler hdl; 658c2ecf20Sopenharmony_ci struct { 668c2ecf20Sopenharmony_ci /* bass/treble cluster */ 678c2ecf20Sopenharmony_ci struct v4l2_ctrl *bass; 688c2ecf20Sopenharmony_ci struct v4l2_ctrl *treble; 698c2ecf20Sopenharmony_ci }; 708c2ecf20Sopenharmony_ci struct { 718c2ecf20Sopenharmony_ci /* mute/balance cluster */ 728c2ecf20Sopenharmony_ci struct v4l2_ctrl *mute; 738c2ecf20Sopenharmony_ci struct v4l2_ctrl *balance; 748c2ecf20Sopenharmony_ci }; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic inline struct tda7432 *to_state(struct v4l2_subdev *sd) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci return container_of(sd, struct tda7432, sd); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci return &container_of(ctrl->handler, struct tda7432, hdl)->sd; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* The TDA7432 is made by STS-Thompson 888c2ecf20Sopenharmony_ci * http://www.st.com 898c2ecf20Sopenharmony_ci * http://us.st.com/stonline/books/pdf/docs/4056.pdf 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * TDA7432: I2C-bus controlled basic audio processor 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * The TDA7432 controls basic audio functions like volume, balance, 948c2ecf20Sopenharmony_ci * and tone control (including loudness). It also has four channel 958c2ecf20Sopenharmony_ci * output (for front and rear). Since most vidcap cards probably 968c2ecf20Sopenharmony_ci * don't have 4 channel output, this driver will set front & rear 978c2ecf20Sopenharmony_ci * together (no independent control). 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Subaddresses for TDA7432 */ 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define TDA7432_IN 0x00 /* Input select */ 1038c2ecf20Sopenharmony_ci#define TDA7432_VL 0x01 /* Volume */ 1048c2ecf20Sopenharmony_ci#define TDA7432_TN 0x02 /* Bass, Treble (Tone) */ 1058c2ecf20Sopenharmony_ci#define TDA7432_LF 0x03 /* Attenuation LF (Left Front) */ 1068c2ecf20Sopenharmony_ci#define TDA7432_LR 0x04 /* Attenuation LR (Left Rear) */ 1078c2ecf20Sopenharmony_ci#define TDA7432_RF 0x05 /* Attenuation RF (Right Front) */ 1088c2ecf20Sopenharmony_ci#define TDA7432_RR 0x06 /* Attenuation RR (Right Rear) */ 1098c2ecf20Sopenharmony_ci#define TDA7432_LD 0x07 /* Loudness */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* Masks for bits in TDA7432 subaddresses */ 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* Many of these not used - just for documentation */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* Subaddress 0x00 - Input selection and bass control */ 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* Bits 0,1,2 control input: 1198c2ecf20Sopenharmony_ci * 0x00 - Stereo input 1208c2ecf20Sopenharmony_ci * 0x02 - Mono input 1218c2ecf20Sopenharmony_ci * 0x03 - Mute (Using Attenuators Plays better with modules) 1228c2ecf20Sopenharmony_ci * Mono probably isn't used - I'm guessing only the stereo 1238c2ecf20Sopenharmony_ci * input is connected on most cards, so we'll set it to stereo. 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * Bit 3 controls bass cut: 0/1 is non-symmetric/symmetric bass cut 1268c2ecf20Sopenharmony_ci * Bit 4 controls bass range: 0/1 is extended/standard bass range 1278c2ecf20Sopenharmony_ci * 1288c2ecf20Sopenharmony_ci * Highest 3 bits not used 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define TDA7432_STEREO_IN 0 1328c2ecf20Sopenharmony_ci#define TDA7432_MONO_IN 2 /* Probably won't be used */ 1338c2ecf20Sopenharmony_ci#define TDA7432_BASS_SYM 1 << 3 1348c2ecf20Sopenharmony_ci#define TDA7432_BASS_NORM 1 << 4 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* Subaddress 0x01 - Volume */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Lower 7 bits control volume from -79dB to +32dB in 1dB steps 1398c2ecf20Sopenharmony_ci * Recommended maximum is +20 dB 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * +32dB: 0x00 1428c2ecf20Sopenharmony_ci * +20dB: 0x0c 1438c2ecf20Sopenharmony_ci * 0dB: 0x20 1448c2ecf20Sopenharmony_ci * -79dB: 0x6f 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * MSB (bit 7) controls loudness: 1/0 is loudness on/off 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#define TDA7432_VOL_0DB 0x20 1508c2ecf20Sopenharmony_ci#define TDA7432_LD_ON 1 << 7 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* Subaddress 0x02 - Tone control */ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* Bits 0,1,2 control absolute treble gain from 0dB to 14dB 1568c2ecf20Sopenharmony_ci * 0x0 is 14dB, 0x7 is 0dB 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci * Bit 3 controls treble attenuation/gain (sign) 1598c2ecf20Sopenharmony_ci * 1 = gain (+) 1608c2ecf20Sopenharmony_ci * 0 = attenuation (-) 1618c2ecf20Sopenharmony_ci * 1628c2ecf20Sopenharmony_ci * Bits 4,5,6 control absolute bass gain from 0dB to 14dB 1638c2ecf20Sopenharmony_ci * (This is only true for normal base range, set in 0x00) 1648c2ecf20Sopenharmony_ci * 0x0 << 4 is 14dB, 0x7 is 0dB 1658c2ecf20Sopenharmony_ci * 1668c2ecf20Sopenharmony_ci * Bit 7 controls bass attenuation/gain (sign) 1678c2ecf20Sopenharmony_ci * 1 << 7 = gain (+) 1688c2ecf20Sopenharmony_ci * 0 << 7 = attenuation (-) 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * Example: 1718c2ecf20Sopenharmony_ci * 1 1 0 1 0 1 0 1 is +4dB bass, -4dB treble 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define TDA7432_TREBLE_0DB 0xf 1758c2ecf20Sopenharmony_ci#define TDA7432_TREBLE 7 1768c2ecf20Sopenharmony_ci#define TDA7432_TREBLE_GAIN 1 << 3 1778c2ecf20Sopenharmony_ci#define TDA7432_BASS_0DB 0xf 1788c2ecf20Sopenharmony_ci#define TDA7432_BASS 7 << 4 1798c2ecf20Sopenharmony_ci#define TDA7432_BASS_GAIN 1 << 7 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* Subaddress 0x03 - Left Front attenuation */ 1838c2ecf20Sopenharmony_ci/* Subaddress 0x04 - Left Rear attenuation */ 1848c2ecf20Sopenharmony_ci/* Subaddress 0x05 - Right Front attenuation */ 1858c2ecf20Sopenharmony_ci/* Subaddress 0x06 - Right Rear attenuation */ 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* Bits 0,1,2,3,4 control attenuation from 0dB to -37.5dB 1888c2ecf20Sopenharmony_ci * in 1.5dB steps. 1898c2ecf20Sopenharmony_ci * 1908c2ecf20Sopenharmony_ci * 0x00 is 0dB 1918c2ecf20Sopenharmony_ci * 0x1f is -37.5dB 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * Bit 5 mutes that channel when set (1 = mute, 0 = unmute) 1948c2ecf20Sopenharmony_ci * We'll use the mute on the input, though (above) 1958c2ecf20Sopenharmony_ci * Bits 6,7 unused 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#define TDA7432_ATTEN_0DB 0x00 1998c2ecf20Sopenharmony_ci#define TDA7432_MUTE 0x1 << 5 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* Subaddress 0x07 - Loudness Control */ 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* Bits 0,1,2,3 control loudness from 0dB to -15dB in 1dB steps 2058c2ecf20Sopenharmony_ci * when bit 4 is NOT set 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * 0x0 is 0dB 2088c2ecf20Sopenharmony_ci * 0xf is -15dB 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * If bit 4 is set, then there is a flat attenuation according to 2118c2ecf20Sopenharmony_ci * the lower 4 bits, as above. 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * Bits 5,6,7 unused 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* Begin code */ 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 2238c2ecf20Sopenharmony_ci unsigned char buffer[2]; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci v4l2_dbg(2, debug, sd, "In tda7432_write\n"); 2268c2ecf20Sopenharmony_ci v4l2_dbg(1, debug, sd, "Writing %d 0x%x\n", subaddr, val); 2278c2ecf20Sopenharmony_ci buffer[0] = subaddr; 2288c2ecf20Sopenharmony_ci buffer[1] = val; 2298c2ecf20Sopenharmony_ci if (2 != i2c_master_send(client, buffer, 2)) { 2308c2ecf20Sopenharmony_ci v4l2_err(sd, "I/O error, trying (write %d 0x%x)\n", 2318c2ecf20Sopenharmony_ci subaddr, val); 2328c2ecf20Sopenharmony_ci return -1; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int tda7432_set(struct v4l2_subdev *sd) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 2408c2ecf20Sopenharmony_ci unsigned char buf[16]; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci buf[0] = TDA7432_IN; 2438c2ecf20Sopenharmony_ci buf[1] = TDA7432_STEREO_IN | /* Main (stereo) input */ 2448c2ecf20Sopenharmony_ci TDA7432_BASS_SYM | /* Symmetric bass cut */ 2458c2ecf20Sopenharmony_ci TDA7432_BASS_NORM; /* Normal bass range */ 2468c2ecf20Sopenharmony_ci buf[2] = 0x3b; 2478c2ecf20Sopenharmony_ci if (loudness) /* Turn loudness on? */ 2488c2ecf20Sopenharmony_ci buf[2] |= TDA7432_LD_ON; 2498c2ecf20Sopenharmony_ci buf[3] = TDA7432_TREBLE_0DB | (TDA7432_BASS_0DB << 4); 2508c2ecf20Sopenharmony_ci buf[4] = TDA7432_ATTEN_0DB; 2518c2ecf20Sopenharmony_ci buf[5] = TDA7432_ATTEN_0DB; 2528c2ecf20Sopenharmony_ci buf[6] = TDA7432_ATTEN_0DB; 2538c2ecf20Sopenharmony_ci buf[7] = TDA7432_ATTEN_0DB; 2548c2ecf20Sopenharmony_ci buf[8] = loudness; 2558c2ecf20Sopenharmony_ci if (9 != i2c_master_send(client, buf, 9)) { 2568c2ecf20Sopenharmony_ci v4l2_err(sd, "I/O error, trying tda7432_set\n"); 2578c2ecf20Sopenharmony_ci return -1; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int tda7432_log_status(struct v4l2_subdev *sd) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci struct tda7432 *state = to_state(sd); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci v4l2_ctrl_handler_log_status(&state->hdl, sd->name); 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int tda7432_s_ctrl(struct v4l2_ctrl *ctrl) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = to_sd(ctrl); 2748c2ecf20Sopenharmony_ci struct tda7432 *t = to_state(sd); 2758c2ecf20Sopenharmony_ci u8 bass, treble, volume; 2768c2ecf20Sopenharmony_ci u8 lf, lr, rf, rr; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci switch (ctrl->id) { 2798c2ecf20Sopenharmony_ci case V4L2_CID_AUDIO_MUTE: 2808c2ecf20Sopenharmony_ci if (t->balance->val < 0) { 2818c2ecf20Sopenharmony_ci /* shifted to left, attenuate right */ 2828c2ecf20Sopenharmony_ci rr = rf = -t->balance->val; 2838c2ecf20Sopenharmony_ci lr = lf = TDA7432_ATTEN_0DB; 2848c2ecf20Sopenharmony_ci } else if (t->balance->val > 0) { 2858c2ecf20Sopenharmony_ci /* shifted to right, attenuate left */ 2868c2ecf20Sopenharmony_ci rr = rf = TDA7432_ATTEN_0DB; 2878c2ecf20Sopenharmony_ci lr = lf = t->balance->val; 2888c2ecf20Sopenharmony_ci } else { 2898c2ecf20Sopenharmony_ci /* centered */ 2908c2ecf20Sopenharmony_ci rr = rf = TDA7432_ATTEN_0DB; 2918c2ecf20Sopenharmony_ci lr = lf = TDA7432_ATTEN_0DB; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci if (t->mute->val) { 2948c2ecf20Sopenharmony_ci lf |= TDA7432_MUTE; 2958c2ecf20Sopenharmony_ci lr |= TDA7432_MUTE; 2968c2ecf20Sopenharmony_ci rf |= TDA7432_MUTE; 2978c2ecf20Sopenharmony_ci rr |= TDA7432_MUTE; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci /* Mute & update balance*/ 3008c2ecf20Sopenharmony_ci tda7432_write(sd, TDA7432_LF, lf); 3018c2ecf20Sopenharmony_ci tda7432_write(sd, TDA7432_LR, lr); 3028c2ecf20Sopenharmony_ci tda7432_write(sd, TDA7432_RF, rf); 3038c2ecf20Sopenharmony_ci tda7432_write(sd, TDA7432_RR, rr); 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci case V4L2_CID_AUDIO_VOLUME: 3068c2ecf20Sopenharmony_ci volume = 0x6f - ctrl->val; 3078c2ecf20Sopenharmony_ci if (loudness) /* Turn on the loudness bit */ 3088c2ecf20Sopenharmony_ci volume |= TDA7432_LD_ON; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci tda7432_write(sd, TDA7432_VL, volume); 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci case V4L2_CID_AUDIO_BASS: 3138c2ecf20Sopenharmony_ci bass = t->bass->val; 3148c2ecf20Sopenharmony_ci treble = t->treble->val; 3158c2ecf20Sopenharmony_ci if (bass >= 0x8) 3168c2ecf20Sopenharmony_ci bass = 14 - (bass - 8); 3178c2ecf20Sopenharmony_ci if (treble >= 0x8) 3188c2ecf20Sopenharmony_ci treble = 14 - (treble - 8); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci tda7432_write(sd, TDA7432_TN, 0x10 | (bass << 4) | treble); 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci return -EINVAL; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops tda7432_ctrl_ops = { 3298c2ecf20Sopenharmony_ci .s_ctrl = tda7432_s_ctrl, 3308c2ecf20Sopenharmony_ci}; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops tda7432_core_ops = { 3338c2ecf20Sopenharmony_ci .log_status = tda7432_log_status, 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops tda7432_ops = { 3378c2ecf20Sopenharmony_ci .core = &tda7432_core_ops, 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------- */ 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/* *********************** * 3438c2ecf20Sopenharmony_ci * i2c interface functions * 3448c2ecf20Sopenharmony_ci * *********************** */ 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int tda7432_probe(struct i2c_client *client, 3478c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci struct tda7432 *t; 3508c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci v4l_info(client, "chip found @ 0x%02x (%s)\n", 3538c2ecf20Sopenharmony_ci client->addr << 1, client->adapter->name); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci t = devm_kzalloc(&client->dev, sizeof(*t), GFP_KERNEL); 3568c2ecf20Sopenharmony_ci if (!t) 3578c2ecf20Sopenharmony_ci return -ENOMEM; 3588c2ecf20Sopenharmony_ci sd = &t->sd; 3598c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(sd, client, &tda7432_ops); 3608c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(&t->hdl, 5); 3618c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, 3628c2ecf20Sopenharmony_ci V4L2_CID_AUDIO_VOLUME, 0, maxvol ? 0x68 : 0x4f, 1, maxvol ? 0x5d : 0x47); 3638c2ecf20Sopenharmony_ci t->mute = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, 3648c2ecf20Sopenharmony_ci V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); 3658c2ecf20Sopenharmony_ci t->balance = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, 3668c2ecf20Sopenharmony_ci V4L2_CID_AUDIO_BALANCE, -31, 31, 1, 0); 3678c2ecf20Sopenharmony_ci t->bass = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, 3688c2ecf20Sopenharmony_ci V4L2_CID_AUDIO_BASS, 0, 14, 1, 7); 3698c2ecf20Sopenharmony_ci t->treble = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, 3708c2ecf20Sopenharmony_ci V4L2_CID_AUDIO_TREBLE, 0, 14, 1, 7); 3718c2ecf20Sopenharmony_ci sd->ctrl_handler = &t->hdl; 3728c2ecf20Sopenharmony_ci if (t->hdl.error) { 3738c2ecf20Sopenharmony_ci int err = t->hdl.error; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&t->hdl); 3768c2ecf20Sopenharmony_ci return err; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci v4l2_ctrl_cluster(2, &t->bass); 3798c2ecf20Sopenharmony_ci v4l2_ctrl_cluster(2, &t->mute); 3808c2ecf20Sopenharmony_ci v4l2_ctrl_handler_setup(&t->hdl); 3818c2ecf20Sopenharmony_ci if (loudness < 0 || loudness > 15) { 3828c2ecf20Sopenharmony_ci v4l2_warn(sd, "loudness parameter must be between 0 and 15\n"); 3838c2ecf20Sopenharmony_ci if (loudness < 0) 3848c2ecf20Sopenharmony_ci loudness = 0; 3858c2ecf20Sopenharmony_ci if (loudness > 15) 3868c2ecf20Sopenharmony_ci loudness = 15; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci tda7432_set(sd); 3908c2ecf20Sopenharmony_ci return 0; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic int tda7432_remove(struct i2c_client *client) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 3968c2ecf20Sopenharmony_ci struct tda7432 *t = to_state(sd); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci tda7432_set(sd); 3998c2ecf20Sopenharmony_ci v4l2_device_unregister_subdev(sd); 4008c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&t->hdl); 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic const struct i2c_device_id tda7432_id[] = { 4058c2ecf20Sopenharmony_ci { "tda7432", 0 }, 4068c2ecf20Sopenharmony_ci { } 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tda7432_id); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic struct i2c_driver tda7432_driver = { 4118c2ecf20Sopenharmony_ci .driver = { 4128c2ecf20Sopenharmony_ci .name = "tda7432", 4138c2ecf20Sopenharmony_ci }, 4148c2ecf20Sopenharmony_ci .probe = tda7432_probe, 4158c2ecf20Sopenharmony_ci .remove = tda7432_remove, 4168c2ecf20Sopenharmony_ci .id_table = tda7432_id, 4178c2ecf20Sopenharmony_ci}; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cimodule_i2c_driver(tda7432_driver); 420