1 /* 2 * max9877.c -- amp driver for max9877 3 * 4 * Copyright (C) 2009 Samsung Electronics Co.Ltd 5 * Author: Joonyoung Shim <jy0922.shim@samsung.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or (at your 10 * option) any later version. 11 * 12 */ 13 14 #include <linux/module.h> 15 #include <linux/init.h> 16 #include <linux/i2c.h> 17 #include <linux/regmap.h> 18 #include <sound/soc.h> 19 #include <sound/tlv.h> 20 21 #include "max9877.h" 22 23 static struct regmap *regmap; 24 25 static struct reg_default max9877_regs[] = { 26 { 0, 0x40 }, 27 { 1, 0x00 }, 28 { 2, 0x00 }, 29 { 3, 0x00 }, 30 { 4, 0x49 }, 31 }; 32 33 static int max9877_get_reg(struct snd_kcontrol *kcontrol, 34 struct snd_ctl_elem_value *ucontrol) 35 { 36 struct soc_mixer_control *mc = 37 (struct soc_mixer_control *)kcontrol->private_value; 38 unsigned int reg = mc->reg; 39 unsigned int shift = mc->shift; 40 unsigned int mask = mc->max; 41 unsigned int invert = mc->invert; 42 unsigned int val; 43 int ret; 44 45 ret = regmap_read(regmap, reg, &val); 46 if (ret != 0) 47 return ret; 48 49 ucontrol->value.integer.value[0] = (val >> shift) & mask; 50 51 if (invert) 52 ucontrol->value.integer.value[0] = 53 mask - ucontrol->value.integer.value[0]; 54 55 return 0; 56 } 57 58 static int max9877_set_reg(struct snd_kcontrol *kcontrol, 59 struct snd_ctl_elem_value *ucontrol) 60 { 61 struct soc_mixer_control *mc = 62 (struct soc_mixer_control *)kcontrol->private_value; 63 unsigned int reg = mc->reg; 64 unsigned int shift = mc->shift; 65 unsigned int mask = mc->max; 66 unsigned int invert = mc->invert; 67 unsigned int val = (ucontrol->value.integer.value[0] & mask); 68 bool change; 69 int ret; 70 71 if (invert) 72 val = mask - val; 73 74 ret = regmap_update_bits_check(regmap, reg, mask << shift, 75 val << shift, &change); 76 if (ret != 0) 77 return ret; 78 79 if (change) 80 return 1; 81 else 82 return 0; 83 } 84 85 static int max9877_get_2reg(struct snd_kcontrol *kcontrol, 86 struct snd_ctl_elem_value *ucontrol) 87 { 88 struct soc_mixer_control *mc = 89 (struct soc_mixer_control *)kcontrol->private_value; 90 unsigned int reg = mc->reg; 91 unsigned int reg2 = mc->rreg; 92 unsigned int shift = mc->shift; 93 unsigned int mask = mc->max; 94 unsigned int val; 95 int ret; 96 97 ret = regmap_read(regmap, reg, &val); 98 if (ret != 0) 99 return ret; 100 ucontrol->value.integer.value[0] = (val >> shift) & mask; 101 102 ret = regmap_read(regmap, reg2, &val); 103 if (ret != 0) 104 return ret; 105 ucontrol->value.integer.value[1] = (val >> shift) & mask; 106 107 return 0; 108 } 109 110 static int max9877_set_2reg(struct snd_kcontrol *kcontrol, 111 struct snd_ctl_elem_value *ucontrol) 112 { 113 struct soc_mixer_control *mc = 114 (struct soc_mixer_control *)kcontrol->private_value; 115 unsigned int reg = mc->reg; 116 unsigned int reg2 = mc->rreg; 117 unsigned int shift = mc->shift; 118 unsigned int mask = mc->max; 119 unsigned int val = (ucontrol->value.integer.value[0] & mask); 120 unsigned int val2 = (ucontrol->value.integer.value[1] & mask); 121 bool change1, change2; 122 int ret; 123 124 ret = regmap_update_bits_check(regmap, reg, mask << shift, 125 val << shift, &change1); 126 if (ret != 0) 127 return ret; 128 129 ret = regmap_update_bits_check(regmap, reg2, mask << shift, 130 val2 << shift, &change2); 131 if (ret != 0) 132 return ret; 133 134 if (change1 || change2) 135 return 1; 136 else 137 return 0; 138 } 139 140 static int max9877_get_out_mode(struct snd_kcontrol *kcontrol, 141 struct snd_ctl_elem_value *ucontrol) 142 { 143 unsigned int val; 144 int ret; 145 146 ret = regmap_read(regmap, MAX9877_OUTPUT_MODE, &val); 147 if (ret != 0) 148 return ret; 149 150 val &= MAX9877_OUTMODE_MASK; 151 if (val) 152 val--; 153 154 ucontrol->value.integer.value[0] = val; 155 156 return 0; 157 } 158 159 static int max9877_set_out_mode(struct snd_kcontrol *kcontrol, 160 struct snd_ctl_elem_value *ucontrol) 161 { 162 unsigned int val; 163 bool change; 164 int ret; 165 166 val = ucontrol->value.integer.value[0] + 1; 167 168 ret = regmap_update_bits_check(regmap, MAX9877_OUTPUT_MODE, 169 MAX9877_OUTMODE_MASK, val, &change); 170 if (ret != 0) 171 return ret; 172 173 if (change) 174 return 1; 175 else 176 return 0; 177 } 178 179 static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol, 180 struct snd_ctl_elem_value *ucontrol) 181 { 182 unsigned int val; 183 int ret; 184 185 ret = regmap_read(regmap, MAX9877_OUTPUT_MODE, &val); 186 if (ret != 0) 187 return ret; 188 189 val &= MAX9877_OSC_MASK; 190 val >>= MAX9877_OSC_OFFSET; 191 192 ucontrol->value.integer.value[0] = val; 193 194 return 0; 195 } 196 197 static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol, 198 struct snd_ctl_elem_value *ucontrol) 199 { 200 unsigned int val; 201 bool change; 202 int ret; 203 204 val = ucontrol->value.integer.value[0] << MAX9877_OSC_OFFSET; 205 ret = regmap_update_bits_check(regmap, MAX9877_OUTPUT_MODE, 206 MAX9877_OSC_MASK, val, &change); 207 if (ret != 0) 208 return ret; 209 210 if (change) 211 return 1; 212 else 213 return 0; 214 } 215 216 static const unsigned int max9877_pgain_tlv[] = { 217 TLV_DB_RANGE_HEAD(2), 218 0, 1, TLV_DB_SCALE_ITEM(0, 900, 0), 219 2, 2, TLV_DB_SCALE_ITEM(2000, 0, 0), 220 }; 221 222 static const unsigned int max9877_output_tlv[] = { 223 TLV_DB_RANGE_HEAD(4), 224 0, 7, TLV_DB_SCALE_ITEM(-7900, 400, 1), 225 8, 15, TLV_DB_SCALE_ITEM(-4700, 300, 0), 226 16, 23, TLV_DB_SCALE_ITEM(-2300, 200, 0), 227 24, 31, TLV_DB_SCALE_ITEM(-700, 100, 0), 228 }; 229 230 static const char *max9877_out_mode[] = { 231 "INA -> SPK", 232 "INA -> HP", 233 "INA -> SPK and HP", 234 "INB -> SPK", 235 "INB -> HP", 236 "INB -> SPK and HP", 237 "INA + INB -> SPK", 238 "INA + INB -> HP", 239 "INA + INB -> SPK and HP", 240 }; 241 242 static const char *max9877_osc_mode[] = { 243 "1176KHz", 244 "1100KHz", 245 "700KHz", 246 }; 247 248 static const struct soc_enum max9877_enum[] = { 249 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode), 250 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode), 251 }; 252 253 static const struct snd_kcontrol_new max9877_controls[] = { 254 SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume", 255 MAX9877_INPUT_MODE, 0, 2, 0, 256 max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), 257 SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume", 258 MAX9877_INPUT_MODE, 2, 2, 0, 259 max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), 260 SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume", 261 MAX9877_SPK_VOLUME, 0, 31, 0, 262 max9877_get_reg, max9877_set_reg, max9877_output_tlv), 263 SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume", 264 MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, 265 max9877_get_2reg, max9877_set_2reg, max9877_output_tlv), 266 SOC_SINGLE_EXT("MAX9877 INB Stereo Switch", 267 MAX9877_INPUT_MODE, 4, 1, 1, 268 max9877_get_reg, max9877_set_reg), 269 SOC_SINGLE_EXT("MAX9877 INA Stereo Switch", 270 MAX9877_INPUT_MODE, 5, 1, 1, 271 max9877_get_reg, max9877_set_reg), 272 SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch", 273 MAX9877_INPUT_MODE, 6, 1, 0, 274 max9877_get_reg, max9877_set_reg), 275 SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch", 276 MAX9877_OUTPUT_MODE, 6, 1, 0, 277 max9877_get_reg, max9877_set_reg), 278 SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch", 279 MAX9877_OUTPUT_MODE, 7, 1, 1, 280 max9877_get_reg, max9877_set_reg), 281 SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0], 282 max9877_get_out_mode, max9877_set_out_mode), 283 SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1], 284 max9877_get_osc_mode, max9877_set_osc_mode), 285 }; 286 287 /* This function is called from ASoC machine driver */ 288 int max9877_add_controls(struct snd_soc_codec *codec) 289 { 290 return snd_soc_add_codec_controls(codec, max9877_controls, 291 ARRAY_SIZE(max9877_controls)); 292 } 293 EXPORT_SYMBOL_GPL(max9877_add_controls); 294 295 static const struct regmap_config max9877_regmap = { 296 .reg_bits = 8, 297 .val_bits = 8, 298 299 .reg_defaults = max9877_regs, 300 .num_reg_defaults = ARRAY_SIZE(max9877_regs), 301 .cache_type = REGCACHE_RBTREE, 302 }; 303 304 static int max9877_i2c_probe(struct i2c_client *client, 305 const struct i2c_device_id *id) 306 { 307 int i; 308 309 regmap = devm_regmap_init_i2c(client, &max9877_regmap); 310 if (IS_ERR(regmap)) 311 return PTR_ERR(regmap); 312 313 /* Ensure the device is in reset state */ 314 for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) 315 regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def); 316 317 return 0; 318 } 319 320 static int max9877_i2c_remove(struct i2c_client *client) 321 { 322 regmap = NULL; 323 324 return 0; 325 } 326 327 static const struct i2c_device_id max9877_i2c_id[] = { 328 { "max9877", 0 }, 329 { } 330 }; 331 MODULE_DEVICE_TABLE(i2c, max9877_i2c_id); 332 333 static struct i2c_driver max9877_i2c_driver = { 334 .driver = { 335 .name = "max9877", 336 .owner = THIS_MODULE, 337 }, 338 .probe = max9877_i2c_probe, 339 .remove = max9877_i2c_remove, 340 .id_table = max9877_i2c_id, 341 }; 342 343 module_i2c_driver(max9877_i2c_driver); 344 345 MODULE_DESCRIPTION("ASoC MAX9877 amp driver"); 346 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 347 MODULE_LICENSE("GPL"); 348