/* * Copyright (C) 2014 NXP Semiconductors, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ #define pr_fmt(fmt) "%s(): " fmt, __func__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "tfa98xx.h" #include "tfa.h" /* required for enum tfa9912_irq */ #include "tfa98xx_tfafieldnames.h" #define TFA98XX_VERSION TFA98XX_API_REV_STR #define I2C_RETRIES 50 #define I2C_RETRY_DELAY 5 /* ms */ #define ERR -1 /* Change volume selection behavior: * Uncomment following line to generate a profile change when updating * a volume control (also changes to the profile of the modified volume * control) */ /*#define TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL 1 */ /* Supported rates and data formats */ #define TFA98XX_RATES SNDRV_PCM_RATE_8000_48000 #define TFA98XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) #define TF98XX_MAX_DSP_START_TRY_COUNT 10 /* data accessible by all instances */ /* Memory pool used for DSP messages */ static struct kmem_cache *tfa98xx_cache; /* Mutex protected data */ static DEFINE_MUTEX(tfa98xx_mutex); static LIST_HEAD(tfa98xx_device_list); static int tfa98xx_device_count; static int tfa98xx_sync_count; static LIST_HEAD(profile_list); /* list of user selectable profiles */ static int tfa98xx_mixer_profiles; /* number of user selectable profiles */ static int tfa98xx_mixer_profile; /* current mixer profile */ static struct snd_kcontrol_new *tfa98xx_controls; static nxpTfaContainer_t *tfa98xx_container; static int tfa98xx_kmsg_regs; static int tfa98xx_ftrace_regs; static char *fw_name = "tfa98xx.cnt"; module_param(fw_name, charp, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(fw_name, "TFA98xx DSP firmware (container file) name."); static int trace_level; module_param(trace_level, int, S_IRUGO); MODULE_PARM_DESC(trace_level, "TFA98xx debug trace level (0=off, bits:1=verbose,2=regdmesg,3=regftrace,4=timing)."); static char *dflt_prof_name = ""; module_param(dflt_prof_name, charp, S_IRUGO); static int no_start; module_param(no_start, int, S_IRUGO); MODULE_PARM_DESC(no_start, "do not start the work queue; for debugging via user\n"); static int no_reset; module_param(no_reset, int, S_IRUGO); MODULE_PARM_DESC(no_reset, "do not use the reset line; for debugging via user\n"); static int pcm_sample_format; module_param(pcm_sample_format, int, S_IRUGO); MODULE_PARM_DESC(pcm_sample_format, "PCM sample format: 0=S16_LE, 1=S24_LE, 2=S32_LE\n"); static int pcm_no_constraint; module_param(pcm_no_constraint, int, S_IRUGO); MODULE_PARM_DESC(pcm_no_constraint, "do not use constraints for PCM parameters\n"); static void tfa98xx_tapdet_check_update(struct tfa98xx *tfa98xx); static int tfa98xx_get_fssel(unsigned int rate); static void tfa98xx_interrupt_enable(struct tfa98xx *tfa98xx, bool enable); static int get_profile_from_list(char *buf, int id); static int get_profile_id_for_sr(int id, unsigned int rate); struct tfa98xx_rate { unsigned int rate; unsigned int fssel; }; static const struct tfa98xx_rate rate_to_fssel[] = { { 8000, 0 }, { 11025, 1 }, { 12000, 2 }, { 16000, 3 }, { 22050, 4 }, { 24000, 5 }, { 32000, 6 }, { 44100, 7 }, { 48000, 8 }, }; static inline char *tfa_cont_profile_name(struct tfa98xx *tfa98xx, int prof_idx) { if (tfa98xx->tfa->cnt == NULL) return NULL; return tfaContProfileName(tfa98xx->tfa->cnt, tfa98xx->tfa->dev_idx, prof_idx); } static enum tfa_error tfa98xx_write_re25(struct tfa_device *tfa, int value) { enum tfa_error err; /* clear MTPEX */ err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 0); if (err == tfa_error_ok) { /* set RE25 in shadow regiser */ err = tfa_dev_mtp_set(tfa, TFA_MTP_RE25_PRIM, value); } if (err == tfa_error_ok) { /* set MTPEX to copy RE25 into MTP */ err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 2); } return err; } /* Wrapper for tfa start */ static enum tfa_error tfa98xx_tfa_start(struct tfa98xx *tfa98xx, int next_profile, int vstep) { enum tfa_error err; ktime_t start_time, stop_time; u64 delta_time; if (trace_level & 8) start_time = ktime_get_boottime(); err = tfa_dev_start(tfa98xx->tfa, next_profile, vstep); if (trace_level & 8) { stop_time = ktime_get_boottime(); delta_time = ktime_to_ns(ktime_sub(stop_time, start_time)); do_div(delta_time, 1000); dev_dbg(&tfa98xx->i2c->dev, "tfa_dev_start(%d,%d) time = %lld us\n", next_profile, vstep, delta_time); } if ((err == tfa_error_ok) && (tfa98xx->set_mtp_cal)) { enum tfa_error err_cal; err_cal = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); if (err_cal != tfa_error_ok) { pr_err("Error, setting calibration value in mtp, err=%d\n", err_cal); } else { tfa98xx->set_mtp_cal = false; pr_info("Calibration value (%d) set in mtp\n", tfa98xx->cal_data); } } /* Check and update tap-detection state (in case of profile change) */ tfa98xx_tapdet_check_update(tfa98xx); /* Remove sticky bit by reading it once */ tfa_get_noclk(tfa98xx->tfa); /* A cold start erases the configuration, including interrupts setting. * Restore it if required */ tfa98xx_interrupt_enable(tfa98xx, true); return err; } static int tfa98xx_input_open(struct input_dev *dev) { struct tfa98xx *tfa98xx = input_get_drvdata(dev); dev_dbg(tfa98xx->codec->dev, "opening device file\n"); /* note: open function is called only once by the framework. * No need to count number of open file instances. */ if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { dev_dbg(&tfa98xx->i2c->dev, "DSP not loaded, cannot start tap-detection\n"); return -EIO; } /* enable tap-detection service */ tfa98xx->tapdet_open = true; tfa98xx_tapdet_check_update(tfa98xx); return 0; } static void tfa98xx_input_close(struct input_dev *dev) { struct tfa98xx *tfa98xx = input_get_drvdata(dev); dev_dbg(tfa98xx->codec->dev, "closing device file\n"); /* Note: close function is called if the device is unregistered */ /* disable tap-detection service */ tfa98xx->tapdet_open = false; tfa98xx_tapdet_check_update(tfa98xx); } static int tfa98xx_register_inputdev(struct tfa98xx *tfa98xx) { int err; struct input_dev *input; input = input_allocate_device(); if (!input) { dev_err(tfa98xx->codec->dev, "Unable to allocate input device\n"); return -ENOMEM; } input->evbit[0] = BIT_MASK(EV_KEY); input->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); input->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); input->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); input->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); input->keybit[BIT_WORD(BTN_4)] |= BIT_MASK(BTN_4); input->keybit[BIT_WORD(BTN_5)] |= BIT_MASK(BTN_5); input->keybit[BIT_WORD(BTN_6)] |= BIT_MASK(BTN_6); input->keybit[BIT_WORD(BTN_7)] |= BIT_MASK(BTN_7); input->keybit[BIT_WORD(BTN_8)] |= BIT_MASK(BTN_8); input->keybit[BIT_WORD(BTN_9)] |= BIT_MASK(BTN_9); input->open = tfa98xx_input_open; input->close = tfa98xx_input_close; input->name = "tfa98xx-tapdetect"; input->id.bustype = BUS_I2C; input_set_drvdata(input, tfa98xx); err = input_register_device(input); if (err) { dev_err(tfa98xx->codec->dev, "Unable to register input device\n"); goto err_free_dev; } dev_dbg(tfa98xx->codec->dev, "Input device for tap-detection registered: %s\n", input->name); tfa98xx->input = input; return 0; err_free_dev: input_free_device(input); return err; } /* * Check if an input device for tap-detection can and shall be registered. * Register it if appropriate. * If already registered, check if still relevant and remove it if necessary. * unregister: true to request inputdev unregistration. */ static void __tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx, bool unregister) { bool tap_profile = false; unsigned int i; for (i = 0; i < tfa_cnt_get_dev_nprof(tfa98xx->tfa); i++) { if (strstr(tfa_cont_profile_name(tfa98xx, i), ".tap")) { tap_profile = true; tfa98xx->tapdet_profiles |= 1 << i; dev_info(tfa98xx->codec->dev, "found a tap-detection profile (%d - %s)\n", i, tfa_cont_profile_name(tfa98xx, i)); } } /* Check for device support: * - at device level * - at container (profile) level */ if (!(tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) || !tap_profile || unregister) { /* No input device supported or required */ if (tfa98xx->input) { input_unregister_device(tfa98xx->input); tfa98xx->input = NULL; } return; } /* input device required */ if (tfa98xx->input) dev_info(tfa98xx->codec->dev, "Input device already registered, skipping\n"); else tfa98xx_register_inputdev(tfa98xx); } static void tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx) { __tfa98xx_inputdev_check_register(tfa98xx, false); } static void tfa98xx_inputdev_unregister(struct tfa98xx *tfa98xx) { __tfa98xx_inputdev_check_register(tfa98xx, true); } #ifdef CONFIG_DEBUG_FS /* OTC reporting * Returns the MTP0 OTC bit value */ static int tfa98xx_dbgfs_otc_get(void *data, u64 *val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); int value; mutex_lock(&tfa98xx->dsp_lock); value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_OTC); mutex_unlock(&tfa98xx->dsp_lock); if (value < 0) { pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, value); return -EIO; } *val = value; pr_debug("[0x%x] OTC : %d\n", tfa98xx->i2c->addr, value); return 0; } static int tfa98xx_dbgfs_otc_set(void *data, u64 val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); enum tfa_error err; if (val != 0 && val != 1) { pr_err("[0x%x] Unexpected value %llu\n", tfa98xx->i2c->addr, val); return -EINVAL; } mutex_lock(&tfa98xx->dsp_lock); err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_OTC, val); mutex_unlock(&tfa98xx->dsp_lock); if (err != tfa_error_ok) { pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); return -EIO; } pr_debug("[0x%x] OTC < %llu\n", tfa98xx->i2c->addr, val); return 0; } static int tfa98xx_dbgfs_mtpex_get(void *data, u64 *val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); int value; mutex_lock(&tfa98xx->dsp_lock); value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX); mutex_unlock(&tfa98xx->dsp_lock); if (value < 0) { pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, value); return -EIO; } *val = value; pr_debug("[0x%x] MTPEX : %d\n", tfa98xx->i2c->addr, value); return 0; } static int tfa98xx_dbgfs_mtpex_set(void *data, u64 val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); enum tfa_error err; if (val != 0) { pr_err("[0x%x] Can only clear MTPEX (0 value expected)\n", tfa98xx->i2c->addr); return -EINVAL; } mutex_lock(&tfa98xx->dsp_lock); err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_EX, val); mutex_unlock(&tfa98xx->dsp_lock); if (err != tfa_error_ok) { pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); return -EIO; } pr_debug("[0x%x] MTPEX < 0\n", tfa98xx->i2c->addr); return 0; } static int tfa98xx_dbgfs_temp_get(void *data, u64 *val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); mutex_lock(&tfa98xx->dsp_lock); *val = tfa98xx_get_exttemp(tfa98xx->tfa); mutex_unlock(&tfa98xx->dsp_lock); pr_debug("[0x%x] TEMP : %llu\n", tfa98xx->i2c->addr, *val); return 0; } static int tfa98xx_dbgfs_temp_set(void *data, u64 val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); mutex_lock(&tfa98xx->dsp_lock); tfa98xx_set_exttemp(tfa98xx->tfa, (short)val); mutex_unlock(&tfa98xx->dsp_lock); pr_debug("[0x%x] TEMP < %llu\n", tfa98xx->i2c->addr, val); return 0; } static ssize_t tfa98xx_dbgfs_start_set(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct i2c_client *i2c = file->private_data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); enum tfa_error ret; char buf[32]; const char ref[] = "please calibrate now"; int buf_size, cal_profile = 0; /* check string length, and account for eol */ if (count > sizeof(ref) + 1 || count < (sizeof(ref) - 1)) return -EINVAL; buf_size = min(count, (size_t)(sizeof(buf) - 1)); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; buf[buf_size] = 0; /* Compare string, excluding the trailing \0 and the potentials eol */ if (strncmp(buf, ref, sizeof(ref) - 1)) return -EINVAL; mutex_lock(&tfa98xx->dsp_lock); ret = (enum tfa_error)tfa_calibrate(tfa98xx->tfa); if (ret == tfa_error_ok) { cal_profile = tfaContGetCalProfile(tfa98xx->tfa); if (cal_profile < 0) { pr_warn("[0x%x] Calibration profile not found\n", tfa98xx->i2c->addr); } ret = tfa98xx_tfa_start(tfa98xx, cal_profile, tfa98xx->vstep); } if (ret == tfa_error_ok) tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); mutex_unlock(&tfa98xx->dsp_lock); if (ret) { pr_info("[0x%x] Calibration start failed (%d)\n", tfa98xx->i2c->addr, ret); return -EIO; } else { pr_info("[0x%x] Calibration started\n", tfa98xx->i2c->addr); } return count; } static ssize_t tfa98xx_dbgfs_r_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct i2c_client *i2c = file->private_data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); char *str; uint16_t status; int ret; mutex_lock(&tfa98xx->dsp_lock); /* Need to ensure DSP is access-able, use mtp read access for this * purpose */ ret = tfa98xx_get_mtp(tfa98xx->tfa, &status); if (ret) { ret = -EIO; pr_err("[0x%x] MTP read failed\n", tfa98xx->i2c->addr); goto r_c_err; } ret = tfaRunSpeakerCalibration(tfa98xx->tfa); if (ret) { ret = -EIO; pr_err("[0x%x] calibration failed\n", tfa98xx->i2c->addr); goto r_c_err; } str = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!str) { ret = -ENOMEM; pr_err("[0x%x] memory allocation failed\n", tfa98xx->i2c->addr); goto r_c_err; } if (tfa98xx->tfa->spkr_count > 1) { ret = snprintf(str, PAGE_SIZE, "Prim:%d mOhms, Sec:%d mOhms\n", tfa98xx->tfa->mohm[0], tfa98xx->tfa->mohm[1]); } else { ret = snprintf(str, PAGE_SIZE, "Prim:%d mOhms\n", tfa98xx->tfa->mohm[0]); } pr_debug("[0x%x] calib_done: %s", tfa98xx->i2c->addr, str); if (ret < 0) goto r_err; ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); r_err: kfree(str); r_c_err: mutex_unlock(&tfa98xx->dsp_lock); return ret; } static ssize_t tfa98xx_dbgfs_version_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { char str[] = TFA98XX_VERSION "\n"; int ret; ret = simple_read_from_buffer(user_buf, count, ppos, str, sizeof(str)); return ret; } static ssize_t tfa98xx_dbgfs_dsp_state_get(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct i2c_client *i2c = file->private_data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); int ret = 0; char *str; switch (tfa98xx->dsp_init) { case TFA98XX_DSP_INIT_STOPPED: str = "Stopped\n"; break; case TFA98XX_DSP_INIT_RECOVER: str = "Recover requested\n"; break; case TFA98XX_DSP_INIT_FAIL: str = "Failed init\n"; break; case TFA98XX_DSP_INIT_PENDING: str = "Pending init\n"; break; case TFA98XX_DSP_INIT_DONE: str = "Init complete\n"; break; default: str = "Invalid\n"; } pr_debug("[0x%x] dsp_state : %s\n", tfa98xx->i2c->addr, str); ret = simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); return ret; } static ssize_t tfa98xx_dbgfs_dsp_state_set(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct i2c_client *i2c = file->private_data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); enum tfa_error ret; char buf[32]; const char start_cmd[] = "start"; const char stop_cmd[] = "stop"; const char mon_start_cmd[] = "monitor start"; const char mon_stop_cmd[] = "monitor stop"; int buf_size; buf_size = min(count, (size_t)(sizeof(buf) - 1)); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; buf[buf_size] = 0; /* Compare strings, excluding the trailing \0 */ if (!strncmp(buf, start_cmd, sizeof(start_cmd) - 1)) { pr_info("[0x%x] Manual triggering of dsp start...\n", tfa98xx->i2c->addr); mutex_lock(&tfa98xx->dsp_lock); ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); mutex_unlock(&tfa98xx->dsp_lock); pr_debug("[0x%x] tfa_dev_start complete: %d\n", tfa98xx->i2c->addr, ret); } else if (!strncmp(buf, stop_cmd, sizeof(stop_cmd) - 1)) { pr_info("[0x%x] Manual triggering of dsp stop...\n", tfa98xx->i2c->addr); mutex_lock(&tfa98xx->dsp_lock); ret = tfa_dev_stop(tfa98xx->tfa); mutex_unlock(&tfa98xx->dsp_lock); pr_debug("[0x%x] tfa_dev_stop complete: %d\n", tfa98xx->i2c->addr, ret); } else if (!strncmp(buf, mon_start_cmd, sizeof(mon_start_cmd) - 1)) { pr_info("[0x%x] Manual start of monitor thread...\n", tfa98xx->i2c->addr); queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->monitor_work, HZ); } else if (!strncmp(buf, mon_stop_cmd, sizeof(mon_stop_cmd) - 1)) { pr_info("[0x%x] Manual stop of monitor thread...\n", tfa98xx->i2c->addr); cancel_delayed_work_sync(&tfa98xx->monitor_work); } else { return -EINVAL; } return count; } static ssize_t tfa98xx_dbgfs_fw_state_get(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct i2c_client *i2c = file->private_data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); char *str; switch (tfa98xx->dsp_fw_state) { case TFA98XX_DSP_FW_NONE: str = "None\n"; break; case TFA98XX_DSP_FW_PENDING: str = "Pending\n"; break; case TFA98XX_DSP_FW_FAIL: str = "Fail\n"; break; case TFA98XX_DSP_FW_OK: str = "Ok\n"; break; default: str = "Invalid\n"; } pr_debug("[0x%x] fw_state : %s", tfa98xx->i2c->addr, str); return simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); } static ssize_t tfa98xx_dbgfs_rpc_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct i2c_client *i2c = file->private_data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); int ret = 0; uint8_t *buffer; enum Tfa98xx_Error error; if (tfa98xx->tfa == NULL) { pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); return -ENODEV; } if (count == 0) return 0; buffer = kmalloc(count, GFP_KERNEL); if (buffer == NULL) { pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); return -ENOMEM; } mutex_lock(&tfa98xx->dsp_lock); error = dsp_msg_read(tfa98xx->tfa, count, buffer); mutex_unlock(&tfa98xx->dsp_lock); if (error != Tfa98xx_Error_Ok) { pr_debug("[0x%x] dsp_msg_read error: %d\n", tfa98xx->i2c->addr, error); kfree(buffer); return -EFAULT; } ret = copy_to_user(user_buf, buffer, count); kfree(buffer); if (ret) return -EFAULT; *ppos += count; return count; } static ssize_t tfa98xx_dbgfs_rpc_send(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct i2c_client *i2c = file->private_data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); nxpTfaFileDsc_t *msg_file; enum Tfa98xx_Error error; int err = 0; if (tfa98xx->tfa == NULL) { pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); return -ENODEV; } if (count == 0) return 0; /* msg_file.name is not used */ msg_file = kmalloc(count + sizeof(nxpTfaFileDsc_t), GFP_KERNEL); if (msg_file == NULL) { pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); return -ENOMEM; } msg_file->size = count; if (copy_from_user(msg_file->data, user_buf, count)) return -EFAULT; mutex_lock(&tfa98xx->dsp_lock); if ((msg_file->data[0] == 'M') && (msg_file->data[1] == 'G')) { /* int vstep_idx, int vstep_msg_idx both 0 */ error = tfaContWriteFile(tfa98xx->tfa, msg_file, 0, 0); if (error != Tfa98xx_Error_Ok) { pr_debug("[0x%x] tfaContWriteFile error: %d\n", tfa98xx->i2c->addr, error); err = -EIO; } } else { error = dsp_msg(tfa98xx->tfa, msg_file->size, msg_file->data); if (error != Tfa98xx_Error_Ok) { pr_debug("[0x%x] dsp_msg error: %d\n", tfa98xx->i2c->addr, error); err = -EIO; } } mutex_unlock(&tfa98xx->dsp_lock); kfree(msg_file); if (err) return err; return count; } /* -- RPC */ static int tfa98xx_dbgfs_pga_gain_get(void *data, u64 *val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); unsigned int value; value = tfa_get_pga_gain(tfa98xx->tfa); if (value < 0) return -EINVAL; *val = value; return 0; } static int tfa98xx_dbgfs_pga_gain_set(void *data, u64 val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); uint16_t value; int err; value = val & 0xffff; if (value > 7) return -EINVAL; err = tfa_set_pga_gain(tfa98xx->tfa, value); if (err < 0) return -EINVAL; return 0; } DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_otc_fops, tfa98xx_dbgfs_otc_get, tfa98xx_dbgfs_otc_set, "%llu\n"); DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_mtpex_fops, tfa98xx_dbgfs_mtpex_get, tfa98xx_dbgfs_mtpex_set, "%llu\n"); DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_temp_fops, tfa98xx_dbgfs_temp_get, tfa98xx_dbgfs_temp_set, "%llu\n"); DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_pga_gain_fops, tfa98xx_dbgfs_pga_gain_get, tfa98xx_dbgfs_pga_gain_set, "%llu\n"); static const struct file_operations tfa98xx_dbgfs_calib_start_fops = { .owner = THIS_MODULE, .open = simple_open, .write = tfa98xx_dbgfs_start_set, .llseek = default_llseek, }; static const struct file_operations tfa98xx_dbgfs_r_fops = { .owner = THIS_MODULE, .open = simple_open, .read = tfa98xx_dbgfs_r_read, .llseek = default_llseek, }; static const struct file_operations tfa98xx_dbgfs_version_fops = { .owner = THIS_MODULE, .open = simple_open, .read = tfa98xx_dbgfs_version_read, .llseek = default_llseek, }; static const struct file_operations tfa98xx_dbgfs_dsp_state_fops = { .owner = THIS_MODULE, .open = simple_open, .read = tfa98xx_dbgfs_dsp_state_get, .write = tfa98xx_dbgfs_dsp_state_set, .llseek = default_llseek, }; static const struct file_operations tfa98xx_dbgfs_fw_state_fops = { .owner = THIS_MODULE, .open = simple_open, .read = tfa98xx_dbgfs_fw_state_get, .llseek = default_llseek, }; static const struct file_operations tfa98xx_dbgfs_rpc_fops = { .owner = THIS_MODULE, .open = simple_open, .read = tfa98xx_dbgfs_rpc_read, .write = tfa98xx_dbgfs_rpc_send, .llseek = default_llseek, }; static void tfa98xx_debug_init(struct tfa98xx *tfa98xx, struct i2c_client *i2c) { char name[50]; scnprintf(name, MAX_CONTROL_NAME, "%s-%x", i2c->name, i2c->addr); tfa98xx->dbg_dir = debugfs_create_dir(name, NULL); debugfs_create_file("OTC", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_calib_otc_fops); debugfs_create_file("MTPEX", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_calib_mtpex_fops); debugfs_create_file("TEMP", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_calib_temp_fops); debugfs_create_file("calibrate", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_calib_start_fops); debugfs_create_file("R", S_IRUGO, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_r_fops); debugfs_create_file("version", S_IRUGO, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_version_fops); debugfs_create_file("dsp-state", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_dsp_state_fops); debugfs_create_file("fw-state", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_fw_state_fops); debugfs_create_file("rpc", S_IRUGO | S_IWUGO, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_rpc_fops); if (tfa98xx->flags & TFA98XX_FLAG_SAAM_AVAILABLE) { dev_dbg(tfa98xx->dev, "Adding pga_gain debug interface\n"); debugfs_create_file("pga_gain", S_IRUGO, tfa98xx->dbg_dir, tfa98xx->i2c, &tfa98xx_dbgfs_pga_gain_fops); } } static void tfa98xx_debug_remove(struct tfa98xx *tfa98xx) { if (tfa98xx->dbg_dir) debugfs_remove_recursive(tfa98xx->dbg_dir); } #endif /* copies the profile basename (i.e. part until .) into buf */ static void get_profile_basename(char *buf, char *profile) { int cp_len = 0, idx = 0; char *pch; pch = strchr(profile, '.'); idx = pch - profile; cp_len = (pch != NULL) ? idx : (int)strlen(profile); memcpy(buf, profile, cp_len); buf[cp_len] = 0; } /* return the profile name accociated with id from the profile list */ static int get_profile_from_list(char *buf, int id) { struct tfa98xx_baseprofile *bprof; list_for_each_entry(bprof, &profile_list, list) { if (bprof->item_id == id) { strcpy(buf, bprof->basename); return 0; } } return ERR; } /* search for the profile in the profile list */ static int is_profile_in_list(char *profile, int len) { struct tfa98xx_baseprofile *bprof; list_for_each_entry(bprof, &profile_list, list) { if ((len == bprof->len) && (0 == strncmp(bprof->basename, profile, len))) return 1; } return 0; } /* * for the profile with id, look if the requested samplerate is * supported, if found return the (container)profile for this * samplerate, on error or if not found return -1 */ static int get_profile_id_for_sr(int id, unsigned int rate) { int idx = 0; struct tfa98xx_baseprofile *bprof; list_for_each_entry(bprof, &profile_list, list) { if (id == bprof->item_id) { idx = tfa98xx_get_fssel(rate); if (idx < 0) { /* samplerate not supported */ return ERR; } return bprof->sr_rate_sup[idx]; } } /* profile not found */ return ERR; } /* check if this profile is a calibration profile */ static int is_calibration_profile(char *profile) { if (strstr(profile, ".cal") != NULL) return 1; return 0; } /* * adds the (container)profile index of the samplerate found in * the (container)profile to a fixed samplerate table in the (mixer)profile */ static int add_sr_to_profile(struct tfa98xx *tfa98xx, char *basename, int len, int profile) { struct tfa98xx_baseprofile *bprof; int idx = 0; unsigned int sr = 0; list_for_each_entry(bprof, &profile_list, list) { if ((len == bprof->len) && (0 == strncmp(bprof->basename, basename, len))) { /* add supported samplerate for this profile */ sr = tfa98xx_get_profile_sr(tfa98xx->tfa, profile); if (!sr) { pr_err("unable to identify supported sample rate for %s\n", bprof->basename); return ERR; } /* get the index for this samplerate */ idx = tfa98xx_get_fssel(sr); if (idx < 0 || idx >= TFA98XX_NUM_RATES) { pr_err("invalid index for samplerate %d\n", idx); return ERR; } /* enter the (container)profile for this samplerate * at the corresponding index */ bprof->sr_rate_sup[idx] = profile; pr_debug("added profile:samplerate = [%d:%d]\ for mixer profile: %s\n", profile, sr, bprof->basename); } } return 0; } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) static struct snd_soc_codec *snd_soc_kcontrol_codec( struct snd_kcontrol *kcontrol) { return snd_kcontrol_chip(kcontrol); } #endif static int tfa98xx_get_vstep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); int mixer_profile = kcontrol->private_value; int ret = 0; int profile; profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); if (profile < 0) { pr_err("tfa98xx: tfa98xx_get_vstep: invalid profile %d\ (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); return -EINVAL; } mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { int vstep = tfa98xx->prof_vsteps[profile]; ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = tfacont_get_max_vstep(tfa98xx->tfa, profile) - vstep - 1; } mutex_unlock(&tfa98xx_mutex); return ret; } static int tfa98xx_set_vstep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); int mixer_profile = kcontrol->private_value; int profile; int err = 0; int change = 0; if (no_start != 0) return 0; profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); if (profile < 0) { pr_err("tfa98xx: tfa98xx_set_vstep: invalid profile %d\ (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); return -EINVAL; } mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { int vstep, vsteps; int ready = 0; int new_vstep; int value = ucontrol->value.integer.value[tfa98xx->tfa->dev_idx]; vstep = tfa98xx->prof_vsteps[profile]; vsteps = tfacont_get_max_vstep(tfa98xx->tfa, profile); if (vstep == vsteps - value - 1) continue; new_vstep = vsteps - value - 1; if (new_vstep < 0) new_vstep = 0; tfa98xx->prof_vsteps[profile] = new_vstep; #ifndef TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL if (profile == tfa98xx->profile) { #endif /* this is the active profile, program the new vstep */ tfa98xx->vstep = new_vstep; mutex_lock(&tfa98xx->dsp_lock); tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); if (ready) { err = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); if (err) { pr_err("Write vstep error: %d\n", err); } else { pr_debug("Succesfully changed vstep index!\n"); change = 1; } } mutex_unlock(&tfa98xx->dsp_lock); #ifndef TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL } #endif pr_debug("%d: vstep:%d, (control value: %d) - profile %d\n", tfa98xx->tfa->dev_idx, new_vstep, value, profile); } if (change) { list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { mutex_lock(&tfa98xx->dsp_lock); tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); mutex_unlock(&tfa98xx->dsp_lock); } } mutex_unlock(&tfa98xx_mutex); return change; } static int tfa98xx_info_vstep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); int mixer_profile = tfa98xx_mixer_profile; int profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); if (profile < 0) { pr_err("tfa98xx: tfa98xx_info_vstep: invalid profile %d\ (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); return -EINVAL; } uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; mutex_lock(&tfa98xx_mutex); uinfo->count = tfa98xx_device_count; mutex_unlock(&tfa98xx_mutex); uinfo->value.integer.min = 0; uinfo->value.integer.max = max(0, tfacont_get_max_vstep(tfa98xx->tfa, profile) - 1); pr_debug("vsteps count: %d [prof=%d]\n", tfacont_get_max_vstep(tfa98xx->tfa, profile), profile); return 0; } static int tfa98xx_get_profile(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { mutex_lock(&tfa98xx_mutex); ucontrol->value.integer.value[0] = tfa98xx_mixer_profile; mutex_unlock(&tfa98xx_mutex); return 0; } static int tfa98xx_set_profile(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); int change = 0; int new_profile; int prof_idx; int profile_count = tfa98xx_mixer_profiles; int profile = tfa98xx_mixer_profile; if (no_start != 0) return 0; new_profile = ucontrol->value.integer.value[0]; if (new_profile == profile) return 0; if ((new_profile < 0) || (new_profile >= profile_count)) { pr_err("not existing profile (%d)\n", new_profile); return -EINVAL; } /* get the container profile for the requested sample rate */ prof_idx = get_profile_id_for_sr(new_profile, tfa98xx->rate); if (prof_idx < 0) { pr_err("tfa98xx: sample rate [%d] not supported for this \ mixer profile [%d].\n", tfa98xx->rate, new_profile); return 0; } pr_debug("selected container profile [%d]\n", prof_idx); /* update mixer profile */ tfa98xx_mixer_profile = new_profile; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { int err; int ready = 0; /* update 'real' profile (container profile) */ tfa98xx->profile = prof_idx; tfa98xx->vstep = tfa98xx->prof_vsteps[prof_idx]; /* Don't call tfa_dev_start() if there is no clock. */ mutex_lock(&tfa98xx->dsp_lock); tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); if (ready) { /* Also re-enables the interrupts */ err = tfa98xx_tfa_start(tfa98xx, prof_idx, tfa98xx->vstep); if (err) { pr_info("Write profile error: %d\n", err); } else { pr_debug("Changed to profile %d (vstep = %d)\n", prof_idx, tfa98xx->vstep); change = 1; } } mutex_unlock(&tfa98xx->dsp_lock); /* Flag DSP as invalidated as the profile change may invalidate the * current DSP configuration. That way, further stream start can * trigger a tfa_dev_start. */ tfa98xx->dsp_init = TFA98XX_DSP_INIT_INVALIDATED; } if (change) { list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { mutex_lock(&tfa98xx->dsp_lock); tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); mutex_unlock(&tfa98xx->dsp_lock); } } mutex_unlock(&tfa98xx_mutex); return change; } static int tfa98xx_info_profile(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { char profile_name[MAX_CONTROL_NAME] = { 0 }; int count = tfa98xx_mixer_profiles, err = -1; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = count; if (uinfo->value.enumerated.item >= count) uinfo->value.enumerated.item = count - 1; err = get_profile_from_list(profile_name, uinfo->value.enumerated.item); if (err != 0) return -EINVAL; strcpy(uinfo->value.enumerated.name, profile_name); return 0; } static int tfa98xx_info_stop_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; mutex_lock(&tfa98xx_mutex); uinfo->count = tfa98xx_device_count; mutex_unlock(&tfa98xx_mutex); uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0; } static int tfa98xx_get_stop_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = 0; } mutex_unlock(&tfa98xx_mutex); return 0; } static int tfa98xx_set_stop_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { int ready = 0; int i = tfa98xx->tfa->dev_idx; pr_debug("%d: %ld\n", i, ucontrol->value.integer.value[i]); tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); if ((ucontrol->value.integer.value[i] != 0) && ready) { cancel_delayed_work_sync(&tfa98xx->monitor_work); cancel_delayed_work_sync(&tfa98xx->init_work); if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) continue; mutex_lock(&tfa98xx->dsp_lock); tfa_dev_stop(tfa98xx->tfa); tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; mutex_unlock(&tfa98xx->dsp_lock); } ucontrol->value.integer.value[i] = 0; } mutex_unlock(&tfa98xx_mutex); return 1; } static int tfa98xx_info_cal_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; mutex_lock(&tfa98xx_mutex); uinfo->count = tfa98xx_device_count; mutex_unlock(&tfa98xx_mutex); uinfo->value.integer.min = 0; uinfo->value.integer.max = 0xffff; /* 16 bit value */ return 0; } static int tfa98xx_set_cal_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { enum tfa_error err; int i = tfa98xx->tfa->dev_idx; tfa98xx->cal_data = (uint16_t)ucontrol->value.integer.value[i]; mutex_lock(&tfa98xx->dsp_lock); err = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); tfa98xx->set_mtp_cal = (err != tfa_error_ok); if (tfa98xx->set_mtp_cal == false) { pr_info("Calibration value (%d) set in mtp\n", tfa98xx->cal_data); } mutex_unlock(&tfa98xx->dsp_lock); } mutex_unlock(&tfa98xx_mutex); return 1; } static int tfa98xx_get_cal_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { mutex_lock(&tfa98xx->dsp_lock); ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_RE25_PRIM); mutex_unlock(&tfa98xx->dsp_lock); } mutex_unlock(&tfa98xx_mutex); return 0; } static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) { int prof, nprof, mix_index = 0; int nr_controls = 0, id = 0; char *name; struct tfa98xx_baseprofile *bprofile; /* Create the following controls: * - enum control to select the active profile * - one volume control for each profile hosting a vstep * - Stop control on TFA1 devices */ nr_controls = 2; /* Profile and stop control */ if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) nr_controls += 1; /* calibration */ /* allocate the tfa98xx_controls base on the nr of profiles */ nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); for (prof = 0; prof < nprof; prof++) { if (tfacont_get_max_vstep(tfa98xx->tfa, prof)) nr_controls++; /* Playback Volume control */ } tfa98xx_controls = devm_kzalloc(tfa98xx->codec->dev, nr_controls * sizeof(tfa98xx_controls[0]), GFP_KERNEL); if (!tfa98xx_controls) return -ENOMEM; /* Create a mixer item for selecting the active profile */ name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s Profile", tfa98xx->fw.name); tfa98xx_controls[mix_index].name = name; tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; tfa98xx_controls[mix_index].info = tfa98xx_info_profile; tfa98xx_controls[mix_index].get = tfa98xx_get_profile; tfa98xx_controls[mix_index].put = tfa98xx_set_profile; /* save number of profiles */ // tfa98xx_controls[mix_index].private_value = profs; mix_index++; /* create mixer items for each profile that has volume */ for (prof = 0; prof < nprof; prof++) { /* create an new empty profile */ bprofile = devm_kzalloc(tfa98xx->codec->dev, sizeof(*bprofile), GFP_KERNEL); if (!bprofile) return -ENOMEM; bprofile->len = 0; bprofile->item_id = -1; INIT_LIST_HEAD(&bprofile->list); /* copy profile name into basename until the . */ get_profile_basename(bprofile->basename, tfa_cont_profile_name(tfa98xx, prof)); bprofile->len = strlen(bprofile->basename); /* * search the profile list for a profile with basename, if it is not * found then add it to the list and add a new mixer control * (if it has vsteps)also, if it is a calibration profile, * do not add it to the list */ if ((is_profile_in_list(bprofile->basename, bprofile->len) == 0) && is_calibration_profile( tfa_cont_profile_name(tfa98xx, prof)) == 0) { /* the profile is not present, add it to the list */ list_add(&bprofile->list, &profile_list); bprofile->item_id = id++; pr_debug("profile added [%d]: %s\n", bprofile->item_id, bprofile->basename); if (tfacont_get_max_vstep(tfa98xx->tfa, prof)) { name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s %s Playback Volume", tfa98xx->fw.name, bprofile->basename); tfa98xx_controls[mix_index].name = name; tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; tfa98xx_controls[mix_index].info = tfa98xx_info_vstep; tfa98xx_controls[mix_index].get = tfa98xx_get_vstep; tfa98xx_controls[mix_index].put = tfa98xx_set_vstep; /* save profile index */ tfa98xx_controls[mix_index].private_value = bprofile->item_id; mix_index++; } } /* look for the basename profile in the list of mixer profiles and * add the container profile index to the supported samplerates * of this mixer profile */ add_sr_to_profile(tfa98xx, bprofile->basename, bprofile->len, prof); } /* set the number of user selectable profiles in the mixer */ tfa98xx_mixer_profiles = id; /* Create a mixer item for stop control on TFA1 */ name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s Stop", tfa98xx->fw.name); tfa98xx_controls[mix_index].name = name; tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; tfa98xx_controls[mix_index].info = tfa98xx_info_stop_ctl; tfa98xx_controls[mix_index].get = tfa98xx_get_stop_ctl; tfa98xx_controls[mix_index].put = tfa98xx_set_stop_ctl; mix_index++; if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) { name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s Calibration", tfa98xx->fw.name); tfa98xx_controls[mix_index].name = name; tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; tfa98xx_controls[mix_index].info = tfa98xx_info_cal_ctl; tfa98xx_controls[mix_index].get = tfa98xx_get_cal_ctl; tfa98xx_controls[mix_index].put = tfa98xx_set_cal_ctl; mix_index++; } return snd_soc_add_codec_controls(tfa98xx->codec, tfa98xx_controls, mix_index); } static void *tfa98xx_devm_kstrdup(struct device *dev, char *buf) { char *str = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); if (!str) return str; memcpy(str, buf, strlen(buf)); return str; } static int tfa98xx_append_i2c_address(struct device *dev, struct i2c_client *i2c, struct snd_soc_dapm_widget *widgets, int num_widgets, struct snd_soc_dai_driver *dai_drv, int num_dai) { char buf[50]; int i; int i2cbus = i2c->adapter->nr; int addr = i2c->addr; if (dai_drv && num_dai > 0) for (i = 0; i < num_dai; i++) { snprintf(buf, 50, "%s-%x-%x", dai_drv[i].name, i2cbus, addr); dai_drv[i].name = tfa98xx_devm_kstrdup(dev, buf); snprintf(buf, 50, "%s-%x-%x", dai_drv[i].playback.stream_name, i2cbus, addr); dai_drv[i].playback.stream_name = tfa98xx_devm_kstrdup(dev, buf); snprintf(buf, 50, "%s-%x-%x", dai_drv[i].capture.stream_name, i2cbus, addr); dai_drv[i].capture.stream_name = tfa98xx_devm_kstrdup(dev, buf); } /* the idea behind this is convert: * SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), * into: * SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback-2-36", * 0, SND_SOC_NOPM, 0, 0), */ if (widgets && num_widgets > 0) for (i = 0; i < num_widgets; i++) { if (!widgets[i].sname) continue; if ((widgets[i].id == snd_soc_dapm_aif_in) || (widgets[i].id == snd_soc_dapm_aif_out)) { snprintf(buf, 50, "%s-%x-%x", widgets[i].sname, i2cbus, addr); widgets[i].sname = tfa98xx_devm_kstrdup(dev, buf); } } return 0; } static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_common[] = { /* Stream widgets */ SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("AIF OUT", "AIF Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_OUTPUT("OUTL"), SND_SOC_DAPM_INPUT("AEC Loopback"), }; static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_stereo[] = { SND_SOC_DAPM_OUTPUT("OUTR"), }; static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_saam[] = { SND_SOC_DAPM_INPUT("SAAM MIC"), }; static struct snd_soc_dapm_widget tfa9888_dapm_inputs[] = { SND_SOC_DAPM_INPUT("DMIC1"), SND_SOC_DAPM_INPUT("DMIC2"), SND_SOC_DAPM_INPUT("DMIC3"), SND_SOC_DAPM_INPUT("DMIC4"), }; static const struct snd_soc_dapm_route tfa98xx_dapm_routes_common[] = { { "OUTL", NULL, "AIF IN" }, { "AIF OUT", NULL, "AEC Loopback" }, }; static const struct snd_soc_dapm_route tfa98xx_dapm_routes_saam[] = { { "AIF OUT", NULL, "SAAM MIC" }, }; static const struct snd_soc_dapm_route tfa98xx_dapm_routes_stereo[] = { { "OUTR", NULL, "AIF IN" }, }; static const struct snd_soc_dapm_route tfa9888_input_dapm_routes[] = { { "AIF OUT", NULL, "DMIC1" }, { "AIF OUT", NULL, "DMIC2" }, { "AIF OUT", NULL, "DMIC3" }, { "AIF OUT", NULL, "DMIC4" }, }; #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0) static struct snd_soc_dapm_context *snd_soc_codec_get_dapm( struct snd_soc_codec *codec) { return &codec->dapm; } #endif static void tfa98xx_add_widgets(struct tfa98xx *tfa98xx) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(tfa98xx->codec); struct snd_soc_dapm_widget *widgets; unsigned int num_dapm_widgets = ARRAY_SIZE(tfa98xx_dapm_widgets_common); widgets = devm_kzalloc(&tfa98xx->i2c->dev, sizeof(struct snd_soc_dapm_widget) * ARRAY_SIZE(tfa98xx_dapm_widgets_common), GFP_KERNEL); if (!widgets) return; memcpy(widgets, tfa98xx_dapm_widgets_common, sizeof(struct snd_soc_dapm_widget) * ARRAY_SIZE(tfa98xx_dapm_widgets_common)); tfa98xx_append_i2c_address(&tfa98xx->i2c->dev, tfa98xx->i2c, widgets, num_dapm_widgets, NULL, 0); snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(tfa98xx_dapm_widgets_common)); snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_common, ARRAY_SIZE(tfa98xx_dapm_routes_common)); if (tfa98xx->flags & TFA98XX_FLAG_STEREO_DEVICE) { snd_soc_dapm_new_controls(dapm, tfa98xx_dapm_widgets_stereo, ARRAY_SIZE(tfa98xx_dapm_widgets_stereo)); snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_stereo, ARRAY_SIZE(tfa98xx_dapm_routes_stereo)); } if (tfa98xx->flags & TFA98XX_FLAG_MULTI_MIC_INPUTS) { snd_soc_dapm_new_controls(dapm, tfa9888_dapm_inputs, ARRAY_SIZE(tfa9888_dapm_inputs)); snd_soc_dapm_add_routes(dapm, tfa9888_input_dapm_routes, ARRAY_SIZE(tfa9888_input_dapm_routes)); } if (tfa98xx->flags & TFA98XX_FLAG_SAAM_AVAILABLE) { snd_soc_dapm_new_controls(dapm, tfa98xx_dapm_widgets_saam, ARRAY_SIZE(tfa98xx_dapm_widgets_saam)); snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_saam, ARRAY_SIZE(tfa98xx_dapm_routes_saam)); } } /* I2C wrapper functions */ enum Tfa98xx_Error tfa98xx_write_register16(struct tfa_device *tfa, unsigned char subaddress, unsigned short value) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; struct tfa98xx *tfa98xx; int ret; int retries = I2C_RETRIES; if (tfa == NULL) { pr_err("No device available\n"); return Tfa98xx_Error_Fail; } tfa98xx = (struct tfa98xx *)tfa->data; if (!tfa98xx || !tfa98xx->regmap) { pr_err("No tfa98xx regmap available\n"); return Tfa98xx_Error_Bad_Parameter; } retry: ret = regmap_write(tfa98xx->regmap, subaddress, value); if (ret < 0) { pr_warn("i2c error, retries left: %d\n", retries); if (retries) { retries--; msleep(I2C_RETRY_DELAY); goto retry; } return Tfa98xx_Error_Fail; } if (tfa98xx_kmsg_regs) dev_dbg(&tfa98xx->i2c->dev, " WR reg=0x%02x, val=0x%04x %s\n", subaddress, value, ret < 0 ? "Error!!" : ""); if (tfa98xx_ftrace_regs) tfa98xx_trace_printk("\tWR reg=0x%02x, val=0x%04x %s\n", subaddress, value, ret < 0 ? "Error!!" : ""); return error; } enum Tfa98xx_Error tfa98xx_read_register16(struct tfa_device *tfa, unsigned char subaddress, unsigned short *val) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; struct tfa98xx *tfa98xx; unsigned int value; int retries = I2C_RETRIES; int ret; if (tfa == NULL) { pr_err("No device available\n"); return Tfa98xx_Error_Fail; } tfa98xx = (struct tfa98xx *)tfa->data; if (!tfa98xx || !tfa98xx->regmap) { pr_err("No tfa98xx regmap available\n"); return Tfa98xx_Error_Bad_Parameter; } retry: ret = regmap_read(tfa98xx->regmap, subaddress, &value); if (ret < 0) { pr_warn("i2c error at subaddress 0x%x, retries left: %d\n", subaddress, retries); if (retries) { retries--; msleep(I2C_RETRY_DELAY); goto retry; } return Tfa98xx_Error_Fail; } *val = value & 0xffff; if (tfa98xx_kmsg_regs) dev_dbg(&tfa98xx->i2c->dev, "RD reg=0x%02x, val=0x%04x %s\n", subaddress, *val, ret < 0 ? "Error!!" : ""); if (tfa98xx_ftrace_regs) tfa98xx_trace_printk("\tRD reg=0x%02x, val=0x%04x %s\n", subaddress, *val, ret < 0 ? "Error!!" : ""); return error; } /* * init external dsp */ enum Tfa98xx_Error tfa98xx_init_dsp(struct tfa_device *tfa) { return Tfa98xx_Error_Not_Supported; } int tfa98xx_get_dsp_status(struct tfa_device *tfa) { return 0; } /* * write external dsp message */ enum Tfa98xx_Error tfa98xx_write_dsp(struct tfa_device *tfa, int num_bytes, const char *command_buffer) { return Tfa98xx_Error_Not_Supported; } /* * read external dsp message */ enum Tfa98xx_Error tfa98xx_read_dsp(struct tfa_device *tfa, int num_bytes, unsigned char *result_buffer) { return Tfa98xx_Error_Not_Supported; } /* * write/read external dsp message */ enum Tfa98xx_Error tfa98xx_writeread_dsp(struct tfa_device *tfa, int command_length, void *command_buffer, int result_length, void *result_buffer) { return Tfa98xx_Error_Not_Supported; } enum Tfa98xx_Error tfa98xx_read_data(struct tfa_device *tfa, unsigned char reg, int len, unsigned char value[]) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; struct tfa98xx *tfa98xx; struct i2c_client *tfa98xx_client; int err; int tries = 0; unsigned char *reg_buf = NULL; struct i2c_msg msgs[] = { { .flags = 0, .len = 1, .buf = NULL, }, { .flags = I2C_M_RD, .len = len, .buf = value, }, }; //GRP_KERNEL also works, reg_buf = (unsigned char *)kmalloc(sizeof(reg), GFP_DMA); if (!reg_buf) { return -ENOMEM;; } *reg_buf = reg; msgs[0].buf = reg_buf; if (tfa == NULL) { pr_err("No device available\n"); return Tfa98xx_Error_Fail; } tfa98xx = (struct tfa98xx *)tfa->data; if (tfa98xx->i2c) { tfa98xx_client = tfa98xx->i2c; msgs[0].addr = tfa98xx_client->addr; msgs[1].addr = tfa98xx_client->addr; do { err = i2c_transfer(tfa98xx_client->adapter, msgs, ARRAY_SIZE(msgs)); if (err != ARRAY_SIZE(msgs)) msleep_interruptible(I2C_RETRY_DELAY); } while ((err != ARRAY_SIZE(msgs)) && (++tries < I2C_RETRIES)); if (err != ARRAY_SIZE(msgs)) { dev_err(&tfa98xx_client->dev, "read transfer error %d\n", err); error = Tfa98xx_Error_Fail; } if (tfa98xx_kmsg_regs) dev_dbg(&tfa98xx_client->dev, "RD-DAT reg=0x%02x, len=%d\n", reg, len); if (tfa98xx_ftrace_regs) tfa98xx_trace_printk("\t\tRD-DAT reg=0x%02x, len=%d\n", reg, len); } else { pr_err("No device available\n"); error = Tfa98xx_Error_Fail; } kfree(reg_buf); return error; } enum Tfa98xx_Error tfa98xx_write_raw(struct tfa_device *tfa, int len, const unsigned char data[]) { enum Tfa98xx_Error error = Tfa98xx_Error_Ok; struct tfa98xx *tfa98xx; int ret; int retries = I2C_RETRIES; if (tfa == NULL) { pr_err("No device available\n"); return Tfa98xx_Error_Fail; } tfa98xx = (struct tfa98xx *)tfa->data; retry: ret = i2c_master_send(tfa98xx->i2c, data, len); if (ret < 0) { pr_warn("i2c error, retries left: %d\n", retries); if (retries) { retries--; msleep(I2C_RETRY_DELAY); goto retry; } } if (ret == len) { if (tfa98xx_kmsg_regs) dev_dbg(&tfa98xx->i2c->dev, " WR-RAW len=%d\n", len); if (tfa98xx_ftrace_regs) tfa98xx_trace_printk("\t\tWR-RAW len=%d\n", len); return Tfa98xx_Error_Ok; } pr_err(" WR-RAW (len=%d) Error I2C send size mismatch %d\n", len, ret); error = Tfa98xx_Error_Fail; return error; } /* Interrupts management */ static void tfa98xx_interrupt_enable_tfa2(struct tfa98xx *tfa98xx, bool enable) { /* Only for 0x72 we need to enable NOCLK interrupts */ if (tfa98xx->flags & TFA98XX_FLAG_REMOVE_PLOP_NOISE) tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_stnoclk, enable); if (tfa98xx->flags & TFA98XX_FLAG_LP_MODES) { /* FIXME: IELP0 does not excist for 9912 */ tfa_irq_ena(tfa98xx->tfa, 36, enable); tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_stclpr, enable); } } /* Check if tap-detection can and shall be enabled. * Configure SPK interrupt accordingly or setup polling mode * Tap-detection shall be active if: * - the service is enabled (tapdet_open), AND * - the current profile is a tap-detection profile * On TFA1 familiy of devices, activating tap-detection means enabling the SPK * interrupt if available. * We also update the tapdet_enabled and tapdet_poll variables. */ static void tfa98xx_tapdet_check_update(struct tfa98xx *tfa98xx) { unsigned int enable = false; /* Support tap-detection on TFA1 family of devices */ if ((tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) == 0) return; if (tfa98xx->tapdet_open && (tfa98xx->tapdet_profiles & (1 << tfa98xx->profile))) enable = true; if (!gpio_is_valid(tfa98xx->irq_gpio)) { /* interrupt not available, setup polling mode */ tfa98xx->tapdet_poll = true; if (enable) queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->tapdet_work, HZ / 10); else cancel_delayed_work_sync(&tfa98xx->tapdet_work); dev_dbg(tfa98xx->codec->dev, "Polling for tap-detection: %s (%d; 0x%x, %d)\n", enable ? "enabled" : "disabled", tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, tfa98xx->profile); } else { dev_dbg(tfa98xx->codec->dev, "Interrupt for tap-detection: %s (%d; 0x%x, %d)\n", enable ? "enabled" : "disabled", tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, tfa98xx->profile); /* enabled interrupt */ tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_sttapdet, enable); } /* check disabled => enabled transition to clear pending events */ if (!tfa98xx->tapdet_enabled && enable) { /* clear pending event if any */ tfa_irq_clear(tfa98xx->tfa, tfa9912_irq_sttapdet); } if (!tfa98xx->tapdet_poll) tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_sttapdet, 1); /* enable again */ } /* global enable / disable interrupts */ static void tfa98xx_interrupt_enable(struct tfa98xx *tfa98xx, bool enable) { if (tfa98xx->flags & TFA98XX_FLAG_SKIP_INTERRUPTS) return; if (tfa98xx->tfa->tfa_family == 2) tfa98xx_interrupt_enable_tfa2(tfa98xx, enable); } /* Firmware management */ static void tfa98xx_container_loaded(const struct firmware *cont, void *context) { nxpTfaContainer_t *container; struct tfa98xx *tfa98xx = context; enum tfa_error tfa_err; int container_size; int ret; tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; if (!cont) { pr_err("Failed to read %s\n", fw_name); return; } pr_debug("loaded %s - size: %zu\n", fw_name, cont->size); mutex_lock(&tfa98xx_mutex); if (tfa98xx_container == NULL) { container = kzalloc(cont->size, GFP_KERNEL); if (container == NULL) { mutex_unlock(&tfa98xx_mutex); release_firmware(cont); pr_err("Error allocating memory\n"); return; } container_size = cont->size; memcpy(container, cont->data, container_size); release_firmware(cont); pr_debug("%.2s%.2s\n", container->version, container->subversion); pr_debug("%.8s\n", container->customer); pr_debug("%.8s\n", container->application); pr_debug("%.8s\n", container->type); pr_debug("%d ndev\n", container->ndev); pr_debug("%d nprof\n", container->nprof); tfa_err = tfa_load_cnt(container, container_size); if (tfa_err != tfa_error_ok) { mutex_unlock(&tfa98xx_mutex); kfree(container); dev_err(tfa98xx->dev, "Cannot load container file, aborting\n"); return; } tfa98xx_container = container; } else { pr_debug("container file already loaded...\n"); container = tfa98xx_container; release_firmware(cont); } mutex_unlock(&tfa98xx_mutex); tfa98xx->tfa->cnt = container; /* i2c transaction limited to 64k (Documentation/i2c/writing-clients) */ tfa98xx->tfa->buffer_size = 65536; /* DSP messages via i2c */ tfa98xx->tfa->has_msg = 0; if (tfa_dev_probe(tfa98xx->i2c->addr, tfa98xx->tfa) != 0) { dev_err(tfa98xx->dev, "Failed to probe TFA98xx @ 0x%.2x\n", tfa98xx->i2c->addr); return; } tfa98xx->tfa->dev_idx = tfa_cont_get_idx(tfa98xx->tfa); if (tfa98xx->tfa->dev_idx < 0) { dev_err(tfa98xx->dev, "Failed to find TFA98xx @ 0x%.2x in \ container file\n", tfa98xx->i2c->addr); return; } /* Enable debug traces */ tfa98xx->tfa->verbose = trace_level & 1; /* prefix is the application name from the cnt */ tfa_cnt_get_app_name(tfa98xx->tfa, tfa98xx->fw.name); /* set default profile/vstep */ tfa98xx->profile = 0; tfa98xx->vstep = 0; /* Override default profile if requested */ if (strcmp(dflt_prof_name, "")) { unsigned int i; int nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); for (i = 0; i < nprof; i++) { if (strcmp(tfa_cont_profile_name(tfa98xx, i), dflt_prof_name) == 0) { tfa98xx->profile = i; dev_info(tfa98xx->dev, "changing default profile to %s (%d)\n", dflt_prof_name, tfa98xx->profile); break; } } if (i >= nprof) dev_info(tfa98xx->dev, "Default profile override failed (%s profile not found)\n", dflt_prof_name); } tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_OK; pr_debug("Firmware init complete\n"); if (no_start != 0) return; /* Only controls for master device */ if (tfa98xx->tfa->dev_idx == 0) tfa98xx_create_controls(tfa98xx); tfa98xx_inputdev_check_register(tfa98xx); if (tfa_is_cold(tfa98xx->tfa) == 0) { pr_debug("Warning: device 0x%.2x is still warm\n", tfa98xx->i2c->addr); tfa_reset(tfa98xx->tfa); } /* Preload settings using internal clock on TFA2 */ if (tfa98xx->tfa->tfa_family == 2) { mutex_lock(&tfa98xx->dsp_lock); ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); if (ret == Tfa98xx_Error_Not_Supported) tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; mutex_unlock(&tfa98xx->dsp_lock); } tfa98xx_interrupt_enable(tfa98xx, true); } static int tfa98xx_load_container(struct tfa98xx *tfa98xx) { tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_PENDING; return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, fw_name, tfa98xx->dev, GFP_KERNEL, tfa98xx, tfa98xx_container_loaded); } static void tfa98xx_tapdet(struct tfa98xx *tfa98xx) { unsigned int tap_pattern; int btn; /* check tap pattern (BTN_0 is "error" wrong tap indication */ tap_pattern = tfa_get_tap_pattern(tfa98xx->tfa); switch (tap_pattern) { case 0xffffffff: pr_info("More than 4 taps detected! (flagTapPattern = -1)\n"); btn = BTN_0; break; case 0xfffffffe: case 0xfe: pr_info("Illegal tap detected!\n"); btn = BTN_0; break; case 0: pr_info("Unrecognized pattern! (flagTapPattern = 0)\n"); btn = BTN_0; break; default: pr_info("Detected pattern: %d\n", tap_pattern); btn = BTN_0 + tap_pattern; break; } input_report_key(tfa98xx->input, btn, 1); input_report_key(tfa98xx->input, btn, 0); input_sync(tfa98xx->input); /* acknowledge event done by clearing interrupt */ } static void tfa98xx_tapdet_work(struct work_struct *work) { struct tfa98xx *tfa98xx; //TODO check is this is still needed for tap polling tfa98xx = container_of(work, struct tfa98xx, tapdet_work.work); if (tfa_irq_get(tfa98xx->tfa, tfa9912_irq_sttapdet)) tfa98xx_tapdet(tfa98xx); queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->tapdet_work, HZ / 10); } static void tfa98xx_monitor(struct work_struct *work) { struct tfa98xx *tfa98xx; enum Tfa98xx_Error error = Tfa98xx_Error_Ok; tfa98xx = container_of(work, struct tfa98xx, monitor_work.work); /* Check for tap-detection - bypass monitor if it is active */ if (!tfa98xx->input) { mutex_lock(&tfa98xx->dsp_lock); error = tfa_status(tfa98xx->tfa); mutex_unlock(&tfa98xx->dsp_lock); if (error == Tfa98xx_Error_DSP_not_running) { if (tfa98xx->dsp_init == TFA98XX_DSP_INIT_DONE) { tfa98xx->dsp_init = TFA98XX_DSP_INIT_RECOVER; queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->init_work, 0); } } } /* reschedule */ queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->monitor_work, 5 * HZ); } static void tfa98xx_dsp_init(struct tfa98xx *tfa98xx) { int ret; bool failed = false; bool reschedule = false; bool sync = false; if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { pr_debug("Skipping tfa_dev_start (no FW: %d)\n", tfa98xx->dsp_fw_state); return; } if (tfa98xx->dsp_init == TFA98XX_DSP_INIT_DONE) { pr_debug("Stream already started, skipping DSP power-on\n"); return; } mutex_lock(&tfa98xx->dsp_lock); tfa98xx->dsp_init = TFA98XX_DSP_INIT_PENDING; if (tfa98xx->init_count < TF98XX_MAX_DSP_START_TRY_COUNT) { /* directly try to start DSP */ ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); if (ret == Tfa98xx_Error_Not_Supported) { tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; dev_err(&tfa98xx->i2c->dev, "Failed starting device\n"); failed = true; } else if (ret != Tfa98xx_Error_Ok) { /* It may fail as we may not have a valid clock at that * time, so re-schedule and re-try later. */ dev_err(&tfa98xx->i2c->dev, "tfa_dev_start failed! (err %d) - %d\n", ret, tfa98xx->init_count); reschedule = true; } else { sync = true; /* Subsystem ready, tfa init complete */ tfa98xx->dsp_init = TFA98XX_DSP_INIT_DONE; dev_dbg(&tfa98xx->i2c->dev, "tfa_dev_start success (%d)\n", tfa98xx->init_count); /* cancel other pending init works */ cancel_delayed_work(&tfa98xx->init_work); tfa98xx->init_count = 0; } } else { /* exceeded max number ot start tentatives, cancel start */ dev_err(&tfa98xx->i2c->dev, "Failed starting device (%d)\n", tfa98xx->init_count); failed = true; } if (reschedule) { /* reschedule this init work for later */ queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->init_work, msecs_to_jiffies(5)); tfa98xx->init_count++; } if (failed) { tfa98xx->dsp_init = TFA98XX_DSP_INIT_FAIL; /* cancel other pending init works */ cancel_delayed_work(&tfa98xx->init_work); tfa98xx->init_count = 0; } mutex_unlock(&tfa98xx->dsp_lock); if (sync) { /* check if all devices have started */ bool do_sync; mutex_lock(&tfa98xx_mutex); if (tfa98xx_sync_count < tfa98xx_device_count) tfa98xx_sync_count++; do_sync = (tfa98xx_sync_count >= tfa98xx_device_count); mutex_unlock(&tfa98xx_mutex); /* when all devices have started then unmute */ if (do_sync) { tfa98xx_sync_count = 0; list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { mutex_lock(&tfa98xx->dsp_lock); tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); /* * start monitor thread to check IC status bit * periodically, and re-init IC to recover if * needed. */ if (tfa98xx->tfa->tfa_family == 1) queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->monitor_work, 1 * HZ); mutex_unlock(&tfa98xx->dsp_lock); } } } } static void tfa98xx_dsp_init_work(struct work_struct *work) { struct tfa98xx *tfa98xx = container_of(work, struct tfa98xx, init_work.work); tfa98xx_dsp_init(tfa98xx); } static void tfa98xx_interrupt(struct work_struct *work) { struct tfa98xx *tfa98xx = container_of(work, struct tfa98xx, interrupt_work.work); pr_info("\n"); if (tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) { /* check for tap interrupt */ if (tfa_irq_get(tfa98xx->tfa, tfa9912_irq_sttapdet)) { tfa98xx_tapdet(tfa98xx); /* clear interrupt */ tfa_irq_clear(tfa98xx->tfa, tfa9912_irq_sttapdet); } } /* TFA98XX_FLAG_TAPDET_AVAILABLE */ if (tfa98xx->flags & TFA98XX_FLAG_REMOVE_PLOP_NOISE) { int start_triggered; mutex_lock(&tfa98xx->dsp_lock); start_triggered = tfa_plop_noise_interrupt(tfa98xx->tfa, tfa98xx->profile, tfa98xx->vstep); /* Only enable when the return value is 1, * otherwise the interrupt is triggered twice */ if (start_triggered) tfa98xx_interrupt_enable(tfa98xx, true); mutex_unlock(&tfa98xx->dsp_lock); } /* TFA98XX_FLAG_REMOVE_PLOP_NOISE */ if (tfa98xx->flags & TFA98XX_FLAG_LP_MODES) tfa_lp_mode_interrupt(tfa98xx->tfa); /* TFA98XX_FLAG_LP_MODES */ /* unmask interrupts masked in IRQ handler */ tfa_irq_unmask(tfa98xx->tfa); } static int tfa98xx_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); unsigned int sr; int len, prof, nprof, idx = 0; char *basename; u64 formats; int err; /* * Support CODEC to CODEC links, * these are called with a NULL runtime pointer. */ if (!substream->runtime) return 0; if (pcm_no_constraint != 0) return 0; switch (pcm_sample_format) { case 1: formats = SNDRV_PCM_FMTBIT_S24_LE; break; case 2: formats = SNDRV_PCM_FMTBIT_S32_LE; break; default: formats = SNDRV_PCM_FMTBIT_S16_LE; break; } err = snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_FORMAT, formats); if (err < 0) return err; if (no_start != 0) return 0; if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { dev_info(codec->dev, "Container file not loaded\n"); return -EINVAL; } basename = kzalloc(MAX_CONTROL_NAME, GFP_KERNEL); if (!basename) return -ENOMEM; /* copy profile name into basename until the . */ get_profile_basename(basename, tfa_cont_profile_name(tfa98xx, tfa98xx->profile)); len = strlen(basename); /* loop over all profiles and get the supported samples rate(s) from * the profiles with the same basename */ nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); tfa98xx->rate_constraint.list = &tfa98xx->rate_constraint_list[0]; tfa98xx->rate_constraint.count = 0; for (prof = 0; prof < nprof; prof++) { if (0 == strncmp(basename, tfa_cont_profile_name(tfa98xx, prof), len)) { /* Check which sample rate is supported with current profile, * and enforce this. */ sr = tfa98xx_get_profile_sr(tfa98xx->tfa, prof); if (!sr) dev_info(codec->dev, "Unable to identify \ supported sample rate\n"); if (tfa98xx->rate_constraint.count >= TFA98XX_NUM_RATES) { dev_err(codec->dev, "too many sample rates\n"); } else { tfa98xx->rate_constraint_list[idx++] = sr; tfa98xx->rate_constraint.count += 1; } } } kfree(basename); return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &tfa98xx->rate_constraint); } static int tfa98xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec_dai->codec); tfa98xx->sysclk = freq; return 0; } static int tfa98xx_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { pr_debug("\n"); return 0; } static int tfa98xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(dai->codec); struct snd_soc_codec *codec = dai->codec; pr_debug("fmt=0x%x\n", fmt); /* Supported mode: regular I2S, slave, or PDM */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { dev_err(codec->dev, "Invalid Codec master mode\n"); return -EINVAL; } break; case SND_SOC_DAIFMT_PDM: break; default: dev_err(codec->dev, "Unsupported DAI format %d\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; } tfa98xx->audio_mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; return 0; } static int tfa98xx_get_fssel(unsigned int rate) { int i; for (i = 0; i < ARRAY_SIZE(rate_to_fssel); i++) { if (rate_to_fssel[i].rate == rate) return rate_to_fssel[i].fssel; } return -EINVAL; } static int tfa98xx_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); unsigned int rate; int prof_idx; /* Supported */ rate = params_rate(params); pr_debug("Requested rate: %d, sample size: %d, physical size: %d\n", rate, snd_pcm_format_width(params_format(params)), snd_pcm_format_physical_width(params_format(params))); if (no_start != 0) return 0; /* check if samplerate is supported for this mixer profile */ prof_idx = get_profile_id_for_sr(tfa98xx_mixer_profile, rate); if (prof_idx < 0) { pr_err("tfa98xx: invalid sample rate %d.\n", rate); return -EINVAL; } pr_debug("mixer profile:container profile = [%d:%d]\n", tfa98xx_mixer_profile, prof_idx); /* update 'real' profile (container profile) */ tfa98xx->profile = prof_idx; /* update to new rate */ tfa98xx->rate = rate; return 0; } static int tfa98xx_mute(struct snd_soc_dai *dai, int mute, int stream) { struct snd_soc_codec *codec = dai->codec; struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); dev_dbg(&tfa98xx->i2c->dev, "%s: state: %d\n", __func__, mute); if (no_start) { pr_debug("no_start parameter set no tfa_dev_start or tfa_dev_stop, returning\n"); return 0; } if (mute) { /* stop DSP only when both playback and capture streams * are deactivated */ if (stream == SNDRV_PCM_STREAM_PLAYBACK) tfa98xx->pstream = 0; else tfa98xx->cstream = 0; if (tfa98xx->pstream != 0 || tfa98xx->cstream != 0) return 0; mutex_lock(&tfa98xx_mutex); tfa98xx_sync_count = 0; mutex_unlock(&tfa98xx_mutex); cancel_delayed_work_sync(&tfa98xx->monitor_work); cancel_delayed_work_sync(&tfa98xx->init_work); if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) return 0; mutex_lock(&tfa98xx->dsp_lock); tfa_dev_stop(tfa98xx->tfa); tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; mutex_unlock(&tfa98xx->dsp_lock); } else { if (stream == SNDRV_PCM_STREAM_PLAYBACK) tfa98xx->pstream = 1; else tfa98xx->cstream = 1; /* Start DSP */ #if 1 if (tfa98xx->dsp_init != TFA98XX_DSP_INIT_PENDING) queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->init_work, 0); #else tfa98xx_dsp_init(tfa98xx); #endif// } return 0; } static const struct snd_soc_dai_ops tfa98xx_dai_ops = { .startup = tfa98xx_startup, .set_fmt = tfa98xx_set_fmt, .set_sysclk = tfa98xx_set_dai_sysclk, .set_tdm_slot = tfa98xx_set_tdm_slot, .hw_params = tfa98xx_hw_params, .mute_stream = tfa98xx_mute, }; static struct snd_soc_dai_driver tfa98xx_dai[] = { { .name = "tfa98xx-aif", .id = 1, .playback = { .stream_name = "AIF Playback", .channels_min = 1, .channels_max = 4, .rates = TFA98XX_RATES, .formats = TFA98XX_FORMATS, }, .capture = { .stream_name = "AIF Capture", .channels_min = 1, .channels_max = 4, .rates = TFA98XX_RATES, .formats = TFA98XX_FORMATS, }, .ops = &tfa98xx_dai_ops, .symmetric_rates = 1, #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) .symmetric_channels = 1, .symmetric_samplebits = 1, #endif }, }; static int tfa98xx_probe(struct snd_soc_codec *codec) { struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); int ret; pr_debug("\n"); /* setup work queue, will be used to initial DSP on first boot up */ tfa98xx->tfa98xx_wq = create_singlethread_workqueue("tfa98xx"); if (!tfa98xx->tfa98xx_wq) return -ENOMEM; INIT_DELAYED_WORK(&tfa98xx->init_work, tfa98xx_dsp_init_work); INIT_DELAYED_WORK(&tfa98xx->monitor_work, tfa98xx_monitor); INIT_DELAYED_WORK(&tfa98xx->interrupt_work, tfa98xx_interrupt); INIT_DELAYED_WORK(&tfa98xx->tapdet_work, tfa98xx_tapdet_work); tfa98xx->codec = codec; ret = tfa98xx_load_container(tfa98xx); pr_debug("Container loading requested: %d\n", ret); #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0) codec->control_data = tfa98xx->regmap; ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); if (ret != 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } #endif tfa98xx_add_widgets(tfa98xx); dev_info(codec->dev, "tfa98xx codec registered (%s)", tfa98xx->fw.name); return ret; } static int tfa98xx_remove(struct snd_soc_codec *codec) { struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); pr_debug("\n"); tfa98xx_interrupt_enable(tfa98xx, false); tfa98xx_inputdev_unregister(tfa98xx); cancel_delayed_work_sync(&tfa98xx->interrupt_work); cancel_delayed_work_sync(&tfa98xx->monitor_work); cancel_delayed_work_sync(&tfa98xx->init_work); cancel_delayed_work_sync(&tfa98xx->tapdet_work); if (tfa98xx->tfa98xx_wq) destroy_workqueue(tfa98xx->tfa98xx_wq); return 0; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) static struct regmap *tfa98xx_get_regmap(struct device *dev) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); return tfa98xx->regmap; } #endif static struct snd_soc_codec_driver soc_codec_dev_tfa98xx = { .probe = tfa98xx_probe, .remove = tfa98xx_remove, #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0) .get_regmap = tfa98xx_get_regmap, #endif }; static bool tfa98xx_writeable_register(struct device *dev, unsigned int reg) { /* enable read access for all registers */ return 1; } static bool tfa98xx_readable_register(struct device *dev, unsigned int reg) { /* enable read access for all registers */ return 1; } static bool tfa98xx_volatile_register(struct device *dev, unsigned int reg) { /* enable read access for all registers */ return 1; } static const struct regmap_config tfa98xx_regmap = { .reg_bits = 8, .val_bits = 16, .max_register = TFA98XX_MAX_REGISTER, .writeable_reg = tfa98xx_writeable_register, .readable_reg = tfa98xx_readable_register, .volatile_reg = tfa98xx_volatile_register, .cache_type = REGCACHE_NONE, }; static void tfa98xx_irq_tfa2(struct tfa98xx *tfa98xx) { pr_info("\n"); /* * mask interrupts * will be unmasked after handling interrupts in workqueue */ tfa_irq_mask(tfa98xx->tfa); queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->interrupt_work, 0); } static irqreturn_t tfa98xx_irq(int irq, void *data) { struct tfa98xx *tfa98xx = data; if (tfa98xx->tfa->tfa_family == 2) tfa98xx_irq_tfa2(tfa98xx); return IRQ_HANDLED; } static int tfa98xx_ext_reset(struct tfa98xx *tfa98xx) { if (tfa98xx && gpio_is_valid(tfa98xx->reset_gpio)) { int reset = tfa98xx->reset_polarity; gpio_set_value_cansleep(tfa98xx->reset_gpio, reset); mdelay(1); gpio_set_value_cansleep(tfa98xx->reset_gpio, !reset); mdelay(1); } return 0; } static int tfa98xx_parse_dt(struct device *dev, struct tfa98xx *tfa98xx, struct device_node *np) { u32 value; int ret; tfa98xx->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); if (tfa98xx->reset_gpio < 0) dev_dbg(dev, "No reset GPIO provided, will not HW reset device\n"); tfa98xx->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); if (tfa98xx->irq_gpio < 0) dev_dbg(dev, "No IRQ GPIO provided.\n"); ret = of_property_read_u32(np, "reset-polarity", &value); if (ret < 0) tfa98xx->reset_polarity = HIGH; else tfa98xx->reset_polarity = (value == 0) ? LOW : HIGH; dev_dbg(dev, "reset-polarity:%d\n", tfa98xx->reset_polarity); return 0; } static ssize_t tfa98xx_reg_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); struct tfa98xx *tfa98xx = dev_get_drvdata(dev); if (count != 1) { pr_debug("invalid register address"); return -EINVAL; } tfa98xx->reg = buf[0]; return 1; } static ssize_t tfa98xx_rw_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); struct tfa98xx *tfa98xx = dev_get_drvdata(dev); u8 *data; int ret; int retries = I2C_RETRIES; data = kmalloc(count + 1, GFP_KERNEL); if (!data) { pr_debug("can not allocate memory\n"); return -ENOMEM; } data[0] = tfa98xx->reg; memcpy(&data[1], buf, count); retry: ret = i2c_master_send(tfa98xx->i2c, data, count + 1); if (ret < 0) { pr_warn("i2c error, retries left: %d\n", retries); if (retries) { retries--; msleep(I2C_RETRY_DELAY); goto retry; } } kfree(data); /* the number of data bytes written without the register address */ return ((ret > 1) ? count : -EIO); } static ssize_t tfa98xx_rw_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct device *dev = container_of(kobj, struct device, kobj); struct tfa98xx *tfa98xx = dev_get_drvdata(dev); struct i2c_msg msgs[] = { { .addr = tfa98xx->i2c->addr, .flags = 0, .len = 1, .buf = &tfa98xx->reg, }, { .addr = tfa98xx->i2c->addr, .flags = I2C_M_RD, .len = count, .buf = buf, }, }; int ret; int retries = I2C_RETRIES; retry: ret = i2c_transfer(tfa98xx->i2c->adapter, msgs, ARRAY_SIZE(msgs)); if (ret < 0) { pr_warn("i2c error, retries left: %d\n", retries); if (retries) { retries--; msleep(I2C_RETRY_DELAY); goto retry; } return ret; } /* ret contains the number of i2c transaction */ /* return the number of bytes read */ return ((ret > 1) ? count : -EIO); } static struct bin_attribute dev_attr_rw = { .attr = { .name = "rw", .mode = S_IRUSR | S_IWUSR, }, .size = 0, .read = tfa98xx_rw_read, .write = tfa98xx_rw_write, }; static struct bin_attribute dev_attr_reg = { .attr = { .name = "reg", .mode = S_IWUSR, }, .size = 0, .read = NULL, .write = tfa98xx_reg_write, }; static int tfa98xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct snd_soc_dai_driver *dai; struct tfa98xx *tfa98xx; struct device_node *np = i2c->dev.of_node; int irq_flags; unsigned int reg; int ret; pr_info("addr=0x%x\n", i2c->addr); if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { dev_err(&i2c->dev, "check_functionality failed\n"); return -EIO; } tfa98xx = devm_kzalloc(&i2c->dev, sizeof(struct tfa98xx), GFP_KERNEL); if (tfa98xx == NULL) return -ENOMEM; tfa98xx->dev = &i2c->dev; tfa98xx->i2c = i2c; tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; tfa98xx->rate = 48000; /* init to the default sample rate (48kHz) */ tfa98xx->tfa = NULL; tfa98xx->regmap = devm_regmap_init_i2c(i2c, &tfa98xx_regmap); if (IS_ERR(tfa98xx->regmap)) { ret = PTR_ERR(tfa98xx->regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ret); return ret; } i2c_set_clientdata(i2c, tfa98xx); mutex_init(&tfa98xx->dsp_lock); init_waitqueue_head(&tfa98xx->wq); if (np) { ret = tfa98xx_parse_dt(&i2c->dev, tfa98xx, np); if (ret) { dev_err(&i2c->dev, "Failed to parse DT node\n"); return ret; } if (no_start) tfa98xx->irq_gpio = -1; if (no_reset) tfa98xx->reset_gpio = -1; } else { tfa98xx->reset_gpio = -1; tfa98xx->irq_gpio = -1; } if (gpio_is_valid(tfa98xx->reset_gpio)) { ret = devm_gpio_request_one(&i2c->dev, tfa98xx->reset_gpio, GPIOF_OUT_INIT_LOW, "TFA98XX_RST"); if (ret) return ret; } if (gpio_is_valid(tfa98xx->irq_gpio)) { ret = devm_gpio_request_one(&i2c->dev, tfa98xx->irq_gpio, GPIOF_DIR_IN, "TFA98XX_INT"); if (ret) return ret; } /* Power up! */ tfa98xx_ext_reset(tfa98xx); if ((no_start == 0) && (no_reset == 0)) { ret = regmap_read(tfa98xx->regmap, 0x03, ®); if (ret < 0) { dev_err(&i2c->dev, "Failed to read Revision register: %d\n", ret); return -EIO; } switch (reg & 0xff) { case 0x72: /* tfa9872 */ pr_info("TFA9872 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; tfa98xx->flags |= TFA98XX_FLAG_REMOVE_PLOP_NOISE; /* tfa98xx->flags |= TFA98XX_FLAG_LP_MODES; */ tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; break; case 0x74: /* tfa9874 */ pr_info("TFA9874 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; break; case 0x78: /* tfa9878 */ pr_info("TFA9878 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; break; case 0x88: /* tfa9888 */ pr_info("TFA9888 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_STEREO_DEVICE; tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; break; case 0x13: /* tfa9912 */ pr_info("TFA9912 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; /* tfa98xx->flags |= TFA98XX_FLAG_TAPDET_AVAILABLE; */ break; case 0x94: /* tfa9894 */ pr_info("TFA9894 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; break; case 0x80: /* tfa9890 */ case 0x81: /* tfa9890 */ pr_info("TFA9890 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; break; case 0x92: /* tfa9891 */ pr_info("TFA9891 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_SAAM_AVAILABLE; tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; break; case 0x12: /* tfa9895 */ pr_info("TFA9895 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; break; case 0x97: pr_info("TFA9897 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; break; case 0x96: pr_info("TFA9896 detected\n"); tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; break; default: pr_info("Unsupported device revision (0x%x)\n", reg & 0xff); return -EINVAL; } } tfa98xx->tfa = devm_kzalloc(&i2c->dev, sizeof(struct tfa_device), GFP_KERNEL); if (tfa98xx->tfa == NULL) return -ENOMEM; tfa98xx->tfa->data = (void *)tfa98xx; tfa98xx->tfa->cachep = tfa98xx_cache; /* Modify the stream names, by appending the i2c device address. * This is used with multicodec, in order to discriminate the devices. * Stream names appear in the dai definition and in the stream. * We create copies of original structures because each device will * have its own instance of this structure, with its own address. */ dai = devm_kzalloc(&i2c->dev, sizeof(tfa98xx_dai), GFP_KERNEL); if (!dai) return -ENOMEM; memcpy(dai, tfa98xx_dai, sizeof(tfa98xx_dai)); tfa98xx_append_i2c_address(&i2c->dev, i2c, NULL, 0, dai, ARRAY_SIZE(tfa98xx_dai)); ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tfa98xx, dai, ARRAY_SIZE(tfa98xx_dai)); if (ret < 0) { dev_err(&i2c->dev, "Failed to register TFA98xx: %d\n", ret); return ret; } if (gpio_is_valid(tfa98xx->irq_gpio) && !(tfa98xx->flags & TFA98XX_FLAG_SKIP_INTERRUPTS)) { /* register irq handler */ irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; ret = devm_request_threaded_irq(&i2c->dev, gpio_to_irq(tfa98xx->irq_gpio), NULL, tfa98xx_irq, irq_flags, "tfa98xx", tfa98xx); if (ret != 0) { dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", gpio_to_irq(tfa98xx->irq_gpio), ret); return ret; } } else { dev_info(&i2c->dev, "Skipping IRQ registration\n"); /* disable feature support if gpio was invalid */ tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; } #ifdef CONFIG_DEBUG_FS if (no_start == 0) tfa98xx_debug_init(tfa98xx, i2c); #endif /* Register the sysfs files for climax backdoor access */ ret = device_create_bin_file(&i2c->dev, &dev_attr_rw); if (ret) dev_info(&i2c->dev, "error creating sysfs files\n"); ret = device_create_bin_file(&i2c->dev, &dev_attr_reg); if (ret) dev_info(&i2c->dev, "error creating sysfs files\n"); pr_info("%s Probe completed successfully!\n", __func__); INIT_LIST_HEAD(&tfa98xx->list); mutex_lock(&tfa98xx_mutex); tfa98xx_device_count++; list_add(&tfa98xx->list, &tfa98xx_device_list); mutex_unlock(&tfa98xx_mutex); return 0; } static int tfa98xx_i2c_remove(struct i2c_client *i2c) { struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); pr_debug("addr=0x%x\n", i2c->addr); tfa98xx_interrupt_enable(tfa98xx, false); cancel_delayed_work_sync(&tfa98xx->interrupt_work); cancel_delayed_work_sync(&tfa98xx->monitor_work); cancel_delayed_work_sync(&tfa98xx->init_work); cancel_delayed_work_sync(&tfa98xx->tapdet_work); device_remove_bin_file(&i2c->dev, &dev_attr_reg); device_remove_bin_file(&i2c->dev, &dev_attr_rw); #ifdef CONFIG_DEBUG_FS tfa98xx_debug_remove(tfa98xx); #endif snd_soc_unregister_codec(&i2c->dev); if (gpio_is_valid(tfa98xx->irq_gpio)) devm_gpio_free(&i2c->dev, tfa98xx->irq_gpio); if (gpio_is_valid(tfa98xx->reset_gpio)) devm_gpio_free(&i2c->dev, tfa98xx->reset_gpio); mutex_lock(&tfa98xx_mutex); list_del(&tfa98xx->list); tfa98xx_device_count--; if (tfa98xx_device_count == 0) { kfree(tfa98xx_container); tfa98xx_container = NULL; } mutex_unlock(&tfa98xx_mutex); return 0; } static const struct i2c_device_id tfa98xx_i2c_id[] = { { "tfa98xx", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, tfa98xx_i2c_id); #ifdef CONFIG_OF static const struct of_device_id tfa98xx_dt_match[] = { {.compatible = "nxp,tfa98xx" }, {.compatible = "nxp,tfa9872" }, {.compatible = "nxp,tfa9874" }, {.compatible = "nxp,tfa9878" }, {.compatible = "nxp,tfa9888" }, {.compatible = "nxp,tfa9890" }, {.compatible = "nxp,tfa9891" }, {.compatible = "nxp,tfa9894" }, {.compatible = "nxp,tfa9895" }, {.compatible = "nxp,tfa9896" }, {.compatible = "nxp,tfa9897" }, {.compatible = "nxp,tfa9912" }, { }, }; #endif static struct i2c_driver tfa98xx_i2c_driver = { .driver = { .name = "tfa98xx", .owner = THIS_MODULE, .of_match_table = of_match_ptr(tfa98xx_dt_match), }, .probe = tfa98xx_i2c_probe, .remove = tfa98xx_i2c_remove, .id_table = tfa98xx_i2c_id, }; static int __init tfa98xx_i2c_init(void) { int ret = 0; pr_info("TFA98XX driver version %s\n", TFA98XX_VERSION); /* Enable debug traces */ tfa98xx_kmsg_regs = trace_level & 2; tfa98xx_ftrace_regs = trace_level & 4; /* Initialize kmem_cache */ /* Cache name /proc/slabinfo */ tfa98xx_cache = kmem_cache_create("tfa98xx_cache", PAGE_SIZE, /* Structure size, we should fit in single page */ 0, /* Structure alignment */ (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD), /* Cache property */ NULL); /* Object constructor */ if (!tfa98xx_cache) { pr_err("tfa98xx can't create memory pool\n"); ret = -ENOMEM; } ret = i2c_add_driver(&tfa98xx_i2c_driver); return ret; } module_init(tfa98xx_i2c_init); static void __exit tfa98xx_i2c_exit(void) { i2c_del_driver(&tfa98xx_i2c_driver); kmem_cache_destroy(tfa98xx_cache); } module_exit(tfa98xx_i2c_exit); MODULE_DESCRIPTION("ASoC TFA98XX driver"); MODULE_LICENSE("GPL");