/* * Copyright (C) 2014-2020 NXP Semiconductors, All Rights Reserved. * Copyright 2020 GOODIX, 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 #include #include "inc/config.h" #include "inc/tfa98xx.h" #include "inc/tfa.h" #include "inc/tfa_internal.h" /* required for enum tfa9912_irq */ #include "inc/tfa98xx_tfafieldnames.h" #define TFA98XX_VERSION TFA98XX_API_REV_STR #define I2C_RETRIES 50 #define I2C_RETRY_DELAY 5 /* ms */ #define TFA_RESET_DELAY 5 /* ms */ #ifdef N1A #include "inc/tfa98xx_genregs_N1A12.h" #else #include "inc/tfa98xx_genregs_N1C.h" #endif #include #define REF_TEMP_DEVICE_NAME "battery" #include #define TFA98XX_VERSION TFA98XX_API_REV_STR /* 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_16000 | SNDRV_PCM_RATE_32000 | \ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) static unsigned int sr_converted = 48000; #define TFA98XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) /* 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 DEFINE_MUTEX(probe_lock); static LIST_HEAD(tfa98xx_device_list); static int tfa98xx_device_count; static int tfa98xx_sync_count; static int tfa98xx_monitor_count; #define MONITOR_COUNT_MAX 5 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 struct tfa_container *tfa98xx_container; static int buf_pool_size[POOL_MAX_INDEX] = { 64 * 1024, 64 * 1024, 64 * 1024, 64 * 1024, 64 * 1024, 8 * 1024 }; static int tfa98xx_kmsg_regs; static int tfa98xx_ftrace_regs; static char *fw_name = "tfa98xx.cnt"; module_param(fw_name, charp, 0644); MODULE_PARM_DESC(fw_name, "TFA98xx DSP firmware (container file) name."); static int trace_level; module_param(trace_level, int, 0444); 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, 0444); static int no_start; module_param(no_start, int, 0444); 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, 0444); MODULE_PARM_DESC(no_reset, "do not use the reset line; for debugging via user\n"); static int pcm_sample_format = -1; /* * Be careful. Setting pcm_sample_format to 3 means * TDM settings will be dynamically adapted, * If there's TDM setting in container file (cnt), * it's to be overwritten with what's specified by hw_params. */ module_param(pcm_sample_format, int, 0444); MODULE_PARM_DESC(pcm_sample_format, "PCM sample format: 0=S16_LE, 1=S24_LE, 2=S32_LE, -1=all\n"); static int pcm_no_constraint; module_param(pcm_no_constraint, int, 0444); MODULE_PARM_DESC(pcm_no_constraint, "do not use constraints for PCM parameters\n"); static void tfa98xx_dsp_init(struct tfa98xx *tfa98xx); 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); static int _tfa98xx_mute(struct tfa98xx *tfa98xx, int mute, int stream); static int _tfa98xx_stop(struct tfa98xx *tfa98xx); static void tfa98xx_check_calibration(struct tfa98xx *tfa98xx); static int tfa98xx_run_calibration(struct tfa98xx *tfa98xx); static void tfa98xx_set_dsp_configured(struct tfa98xx *tfa98xx); static void tfa98xx_container_loaded (const struct firmware *cont, void *context); 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 const unsigned int index_to_rate[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000 }; static inline char *_tfa_cont_profile_name (struct tfa98xx *tfa98xx, int prof_idx) { if (tfa98xx->tfa->cnt == NULL) return NULL; return tfa_cont_profile_name(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 = 0; ktime_t stop_time = 0; 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->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); } } /* 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; } #if defined(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; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } 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 access MTPOTC: %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 (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } 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 access MTPOTC: err %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; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } 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 access MTPEX: %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; enum tfa98xx_error ret; u16 temp_val = DEFAULT_REF_TEMP; int idx, ndev; struct tfa_device *ntfa = NULL; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } if (val != 0) { pr_err("[0x%x] Can only clear MTPEX (0 value expected)\n", tfa98xx->i2c->addr); return -EINVAL; } /* EXT_TEMP */ ret = tfa98xx_read_reference_temp(&temp_val); if (ret) pr_err("error in reading reference temp\n"); ndev = tfa98xx->tfa->dev_count; for (idx = 0; idx < ndev; idx++) { ntfa = tfa98xx_get_tfa_device_from_index(idx); if (ntfa == NULL) continue; tfa98xx_set_exttemp(ntfa, (short)temp_val); } mutex_lock(&tfa98xx->dsp_lock); err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_EX, 0); mutex_unlock(&tfa98xx->dsp_lock); if (err != tfa_error_ok) { pr_err("[0x%x] Unable to access MTPEX: err %d (suspended)\n", tfa98xx->i2c->addr, err); /* suspend until TFA98xx is active */ tfa98xx->tfa->reset_mtpex = 1; 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); if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } 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); if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } 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_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; int ret = 0; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } str = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!str) return -ENOMEM; tfa98xx_check_calibration(tfa98xx); if (tfa98xx->calibrate_done) { pr_info("[0x%x] Calibration Success\n", tfa98xx->i2c->addr); snprintf(str, PAGE_SIZE, "Success\n"); ret = sizeof("Success"); } else { pr_info("[0x%x] Calibration Fail\n", tfa98xx->i2c->addr); snprintf(str, PAGE_SIZE, "Fail\n"); ret = sizeof("Fail"); } ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); kfree(str); return ret; } 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); int ret = 0; char buf[32]; int buf_size; static const char ref[] = "1"; /* "please calibrate now" */ if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } /* 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)) { pr_info("[0x%x] %s: calibration is triggered with %s!\n", tfa98xx->i2c->addr, __func__, ref); return -EINVAL; } ret = tfa98xx_run_calibration(tfa98xx); if (ret < 0) return ret; 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; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } 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 = tfa_run_speaker_calibration(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"; break; } 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]; static const char start_cmd[] = "start"; static const char stop_cmd[] = "stop"; static const char mon_start_cmd[] = "monitor start"; static 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; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } /* 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); tfa98xx_monitor_count = -1; 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"; break; } 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; struct tfa_device *tfa0 = NULL; if (tfa98xx->tfa == NULL) { pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); return -ENODEV; } if (count == 0) return 0; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } if (tfa98xx->pstream == 0 || tfa98xx->tfa->is_configured <= 0) { pr_info("%s: skipped - tfadsp is not active!\n", __func__); return -EIO; } buffer = kmalloc(count, GFP_KERNEL); if (buffer == NULL) { ret = -ENOMEM; pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); return ret; } tfa0 = tfa98xx->tfa; pr_info("%s called (count %d)\n", __func__, (int)count); mutex_lock(&tfa98xx->dsp_lock); error = dsp_msg_read(tfa0, 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); struct tfa_file_dsc *msg_file; enum tfa98xx_error error; struct tfa_device *tfa0 = NULL; int ret = 0; if (tfa98xx->tfa == NULL) { pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); return -ENODEV; } if (count == 0) return 0; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } if (tfa98xx->pstream == 0 || tfa98xx->tfa->is_configured <= 0) { pr_info("%s: skipped - tfadsp is not active!\n", __func__); return -EIO; } /* msg_file.name is not used */ msg_file = kmalloc(count + sizeof(struct tfa_file_dsc), GFP_KERNEL); if (msg_file == NULL) { ret = -ENOMEM; pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); return ret; } msg_file->size = (uint32_t)count; tfa0 = tfa98xx->tfa; if (copy_from_user(msg_file->data, user_buf, count)) { kfree(msg_file); return -EFAULT; } pr_info("%s called\n", __func__); mutex_lock(&tfa98xx->dsp_lock); tfa0->individual_msg = 1; if ((msg_file->data[0] == 'M') && (msg_file->data[1] == 'G')) { /* int vstep_idx, int vstep_msg_idx both 0 */ error = tfa_cont_write_file(tfa0, msg_file, 0, 0); if (error != TFA98XX_ERROR_OK) { pr_debug("[0x%x] tfa_cont_write_file error: %d\n", tfa98xx->i2c->addr, error); ret = -EIO; } } else { error = dsp_msg(tfa0, msg_file->size, msg_file->data); if (error != TFA98XX_ERROR_OK) { pr_debug("[0x%x] dsp_msg error: %d\n", tfa98xx->i2c->addr, error); ret = -EIO; } } mutex_unlock(&tfa98xx->dsp_lock); kfree(msg_file); if (ret) return ret; return count; } /* -- RPC */ /* ++ DSP message fops */ static ssize_t tfa98xx_dbgfs_dsp_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); enum tfa98xx_error error; int ret = 0; uint8_t *buffer; struct tfa_device *tfa0 = NULL; if (tfa98xx->tfa == NULL) { pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); return -ENODEV; } if (count == 0) return 0; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } if (tfa98xx->pstream == 0 || tfa98xx->tfa->is_configured <= 0) { pr_info("%s: skipped - tfadsp is not active!\n", __func__); return -EIO; } buffer = kmalloc(count, GFP_KERNEL); if (buffer == NULL) { ret = -ENOMEM; pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); return ret; } tfa0 = tfa98xx->tfa; pr_info("%s called (count %d)\n", __func__, (int)count); mutex_lock(&tfa98xx->dsp_lock); error = dsp_msg_read(tfa0, count, buffer); mutex_unlock(&tfa98xx->dsp_lock); if (error) { pr_debug("[0x%x] dsp_msg_read error: %d\n", tfa98xx->i2c->addr, error); kfree(buffer); return -EFAULT; } /* ret = simple_read_from_buffer * (user_buf, count, ppos, buffer, count); */ ret = copy_to_user(user_buf, buffer, count); if (ret) { pr_debug("[0x%x] cannot copy buffer to user: %d\n", tfa98xx->i2c->addr, ret); kfree(buffer); return -EFAULT; } kfree(buffer); return count; } static ssize_t tfa98xx_dbgfs_dsp_write(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 tfa98xx_error error; int ret = 0; struct tfa_device *tfa0 = NULL; uint8_t *buffer; if (tfa98xx->tfa == NULL) { pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); return -ENODEV; } if (count == 0) return 0; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } if (tfa98xx->pstream == 0 || tfa98xx->tfa->is_configured <= 0) { pr_info("%s: skipped - tfadsp is not active!\n", __func__); return -EIO; } buffer = kmalloc(count, GFP_KERNEL); if (buffer == NULL) { ret = -ENOMEM; pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); return ret; } tfa0 = tfa98xx->tfa; ret = copy_from_user(buffer, user_buf, count); if (ret) { pr_debug("[0x%x] cannot copy buffer from user: %d\n", tfa98xx->i2c->addr, ret); kfree(buffer); return -EFAULT; } pr_info("%s called\n", __func__); mutex_lock(&tfa98xx->dsp_lock); tfa0->individual_msg = 1; error = dsp_msg(tfa0, count, buffer); mutex_unlock(&tfa98xx->dsp_lock); if (error) { pr_debug("[0x%x] dsp_msg error: %d\n", tfa98xx->i2c->addr, error); kfree(buffer); return -EFAULT; } kfree(buffer); return count; } /* -- DSP */ static ssize_t tfa98xx_dbgfs_spkr_damaged_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; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } str = kmalloc(count, GFP_KERNEL); if (str == NULL) { ret = -ENOMEM; pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); return ret; } scnprintf(str, PAGE_SIZE, "%s\n", (tfa98xx->tfa->spkr_damaged == 1) ? "damaged" : "ready"); ret = simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); kfree(str); return ret; } 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; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } 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; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } value = val & 0xffff; if (value > 7) return -EINVAL; err = tfa_set_pga_gain(tfa98xx->tfa, value); if (err < 0) return -EINVAL; return 0; } static ssize_t tfa98xx_dbgfs_trace_level_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { char out_buf[4] = {0}; int ret = 0; if (count < 1) { pr_err("%s: read size exceeds buf size %zd\n", __func__, count); return 0; } snprintf(out_buf, 4, "%d\n", trace_level); ret = simple_read_from_buffer(user_buf, count, ppos, out_buf, sizeof(out_buf)); return ret; } static ssize_t tfa98xx_dbgfs_trace_level_write(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); int tl = 0; char buf[2] = {0}; if (copy_from_user(buf, user_buf, 1)) return -EFAULT; tl = buf[0] - 48; pr_info("%s: trace_level = %d\n", __func__, tl); if (tl < 0 || tl > 15) return -EFAULT; trace_level = tl; tfa98xx_kmsg_regs = trace_level & 2; tfa98xx_ftrace_regs = trace_level & 4; list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { if (tfa98xx && tfa98xx->tfa) tfa98xx->tfa->verbose = trace_level & 1; } return count; } static ssize_t tfa98xx_dbgfs_show_cal_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 mtp = 0; int mtpex = 0; char out_buf[64] = {0}; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } if (count < 1) { pr_err("%s: read size exceeds buf size %zd\n", __func__, count); return 0; } mtp = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_RE25); mtpex = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX); snprintf(out_buf, 64, "[%s] MTPEX: %d, MTP: %d mOhm\n", tfa_cont_device_name(tfa98xx->tfa->cnt, tfa98xx->tfa->dev_idx), mtpex, mtp); return simple_read_from_buffer(user_buf, count, ppos, out_buf, sizeof(out_buf)); } /* Direct registers access - provide register address in hex */ #define TFA98XX_DEBUGFS_REG_SET(__reg) \ static int tfa98xx_dbgfs_reg_##__reg##_set(void *data, u64 val)\ {\ struct i2c_client *i2c = (struct i2c_client *)data;\ struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c);\ unsigned int ret, value;\ \ ret = regmap_write(tfa98xx->regmap, 0x##__reg, (val & 0xffff));\ value = val & 0xffff;\ return 0;\ } \ static int tfa98xx_dbgfs_reg_##__reg##_get(void *data, u64 *val)\ {\ struct i2c_client *i2c = (struct i2c_client *)data;\ struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c);\ unsigned int value;\ int ret;\ \ ret = regmap_read(tfa98xx->regmap, 0x##__reg, &value);\ *val = value;\ return 0;\ } \ DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_reg_##__reg##_fops,\ tfa98xx_dbgfs_reg_##__reg##_get,\ tfa98xx_dbgfs_reg_##__reg##_set, "0x%llx\n") #define VAL(str) #str #define TOSTRING(str) VAL(str) #define TFA98XX_DEBUGFS_REG_CREATE_FILE(__reg, __name, dbg_dir, i2c) \ debugfs_create_file(TOSTRING(__reg) "-" TOSTRING(__name),\ 0664, dbg_dir, i2c,\ &tfa98xx_dbgfs_reg_##__reg##_fops) TFA98XX_DEBUGFS_REG_SET(00); TFA98XX_DEBUGFS_REG_SET(01); TFA98XX_DEBUGFS_REG_SET(02); TFA98XX_DEBUGFS_REG_SET(03); TFA98XX_DEBUGFS_REG_SET(04); TFA98XX_DEBUGFS_REG_SET(05); TFA98XX_DEBUGFS_REG_SET(06); TFA98XX_DEBUGFS_REG_SET(07); TFA98XX_DEBUGFS_REG_SET(08); TFA98XX_DEBUGFS_REG_SET(09); TFA98XX_DEBUGFS_REG_SET(0A); TFA98XX_DEBUGFS_REG_SET(0B); TFA98XX_DEBUGFS_REG_SET(0F); TFA98XX_DEBUGFS_REG_SET(10); TFA98XX_DEBUGFS_REG_SET(11); TFA98XX_DEBUGFS_REG_SET(12); TFA98XX_DEBUGFS_REG_SET(13); TFA98XX_DEBUGFS_REG_SET(22); TFA98XX_DEBUGFS_REG_SET(25); 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, .read = tfa98xx_dbgfs_start_get, .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 const struct file_operations tfa98xx_dbgfs_dsp_fops = { .open = simple_open, .read = tfa98xx_dbgfs_dsp_read, .write = tfa98xx_dbgfs_dsp_write, .llseek = default_llseek, }; static const struct file_operations tfa98xx_dbgfs_spkr_damaged_fops = { .owner = THIS_MODULE, .open = simple_open, .read = tfa98xx_dbgfs_spkr_damaged_get, .llseek = default_llseek, }; static const struct file_operations tfa98xx_dbgfs_trace_level_fops = { .owner = THIS_MODULE, .open = simple_open, .read = tfa98xx_dbgfs_trace_level_read, .write = tfa98xx_dbgfs_trace_level_write, .llseek = default_llseek, }; static const struct file_operations tfa98xx_dbgfs_show_cal_fops = { .owner = THIS_MODULE, .open = simple_open, .read = tfa98xx_dbgfs_show_cal_read, .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", 0664, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_calib_otc_fops); debugfs_create_file("MTPEX", 0664, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_calib_mtpex_fops); debugfs_create_file("TEMP", 0664, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_calib_temp_fops); debugfs_create_file("calibrate", 0664, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_calib_start_fops); debugfs_create_file("R", 0444, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_r_fops); debugfs_create_file("version", 0444, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_version_fops); debugfs_create_file("dsp-state", 0664, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_dsp_state_fops); debugfs_create_file("fw-state", 0664, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_fw_state_fops); debugfs_create_file("rpc", 0664, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_rpc_fops); debugfs_create_file("dsp", 0644, tfa98xx->dbg_dir, i2c, &tfa98xx_dbgfs_dsp_fops); if (tfa98xx->flags & TFA98XX_FLAG_SAAM_AVAILABLE) { dev_dbg(tfa98xx->dev, "Adding pga_gain debug interface\n"); debugfs_create_file("pga_gain", 0444, tfa98xx->dbg_dir, tfa98xx->i2c, &tfa98xx_dbgfs_pga_gain_fops); } debugfs_create_file("trace-level", 0644, tfa98xx->dbg_dir, tfa98xx->i2c, &tfa98xx_dbgfs_trace_level_fops); debugfs_create_file("mtp", 0644, tfa98xx->dbg_dir, tfa98xx->i2c, &tfa98xx_dbgfs_show_cal_fops); } static void tfa98xx_debug_remove(struct tfa98xx *tfa98xx) { debugfs_remove_recursive(tfa98xx->dbg_dir); } #endif /* CONFIG_DEBUG_FS */ static void tfa98xx_check_calibration(struct tfa98xx *tfa98xx) { unsigned short value = 0; mutex_lock(&tfa98xx->dsp_lock); value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX); mutex_unlock(&tfa98xx->dsp_lock); if (value >= 0) { tfa98xx->calibrate_done = (value) ? 1 : 0; pr_info("[0x%x] calibrate_done = MTPEX (%d)\n", tfa98xx->i2c->addr, tfa98xx->calibrate_done); } else { pr_info("[0x%x] error in reading MTPEX\n", tfa98xx->i2c->addr); tfa98xx->calibrate_done = 0; } } enum tfa98xx_error tfa98xx_set_tfadsp_bypass(struct tfa_device *tfa) { enum tfa98xx_error err = TFA98XX_ERROR_OK; int res_len = 3; unsigned char buf[3] = {0}; int data[2], is_configured = 0; res_len = 3; err = tfa_dsp_cmd_id_write_read(tfa, MODULE_CUSTOM, CUSTOM_PARAM_GET_CONFIGURED, res_len, buf); if (err == TFA98XX_ERROR_OK) { tfa98xx_convert_bytes2data(res_len, buf, data); is_configured = data[0]; pr_info("%s: check if configured (%d)\n", __func__, is_configured); } /* move on if not configured */ if (!is_configured) return err; pr_info("%s: set bypass if configured\n", __func__); memset(buf, 0, 3); /* dummy value */ tfa->individual_msg = 1; err = tfa_dsp_cmd_id_write(tfa, MODULE_CUSTOM, CUSTOM_PARAM_SET_BYPASS, 3, buf); if (err != TFA98XX_ERROR_OK) pr_info("%s: error in setting bypass (err = %d)\n", __func__, err); return err; } static int tfa98xx_run_calibration(struct tfa98xx *tfa98xx0) { struct tfa98xx *tfa98xx; struct tfa_device *tfa; enum tfa_error ret, cal_err = tfa_error_ok; int idx, ndev = tfa98xx_device_count; int cal_profile = 0; u64 otc_val = 1; /* calibration once by default */ u16 temp_val = DEFAULT_REF_TEMP; /* default */ int mtpex[MAX_HANDLES] = {0}; int re25; int temp_calflag = 0; pr_info("%s: begin\n", __func__); if (tfa98xx0->pstream == 0) { pr_info("[0x%x] %s: calibration is available only when channel is enabled!\n", tfa98xx0->i2c->addr, __func__); return -EIO; } /* EXT_TEMP */ ret = tfa98xx_read_reference_temp(&temp_val); if (ret) { pr_err("%s: error in reading reference temp\n", __func__); temp_val = DEFAULT_REF_TEMP; /* default */ } if (tfa98xx0->tfa->is_bypass) pr_debug("%s: skipped setting bypass - tfadsp in bypass\n", __func__); else tfa98xx_set_tfadsp_bypass(tfa98xx0->tfa); for (idx = 0; idx < ndev; idx++) { tfa = tfa98xx_get_tfa_device_from_index(idx); if (tfa == NULL) continue; if (tfa->vval_active) { mtpex[idx] = tfa_dev_mtp_get(tfa, TFA_MTP_EX); pr_info("%s: dev %d - storing MTP (%d -> 0)\n", __func__, idx, mtpex[idx]); } pr_info("%s: dev %d - resetting MTP\n", __func__, idx); /* OTC <0:always 1:once> */ ret = tfa_dev_mtp_set(tfa, TFA_MTP_OTC, otc_val); if (ret) pr_info("setting OTC failed (%d)\n", ret); /* MTPEX */ ret = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 0); if (ret) { pr_info("resetting MTPEX failed (%d)\n", ret); /* suspend until TFA98xx is active */ tfa->reset_mtpex = 1; } if (!tfa->vval_active) { /* MTPEX */ ret = tfa_dev_mtp_set(tfa, TFA_MTP_RE25, 0); /* EXT_TEMP */ tfa98xx_set_exttemp(tfa, temp_val); } pr_info("%s: dev %d - force to enable auto calibration (%s -> enabled)", __func__, idx, (tfa->disable_auto_cal) ? "disabled" : "enabled"); /* enable auto calibration */ temp_calflag |= tfa->disable_auto_cal; tfa->disable_auto_cal = 0; /* force to enable all the devices */ if (tfa->dev_count <= MAX_CHANNELS) tfa->set_active = 1; /* force to mute amplifier to flush buffer */ tfa_run_mute(tfa); } /* wait before restarting for calibration */ msleep_interruptible(10); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { pr_info("%s: dev %d - stopping devices\n", __func__, tfa98xx->tfa->dev_idx); _tfa98xx_stop(tfa98xx); mutex_lock(&tfa98xx->dsp_lock); tfa98xx->calibrate_done = 0; tfa98xx->dsp_init = TFA98XX_DSP_INIT_PENDING; tfa98xx_set_dsp_configured(tfa98xx); mutex_unlock(&tfa98xx->dsp_lock); } pr_info("%s: calibration started!\n", __func__); for (idx = 0; idx < ndev; idx++) { tfa = tfa98xx_get_tfa_device_from_index(idx); if (tfa == NULL) continue; tfa98xx = (struct tfa98xx *)tfa->data; pr_info("%s: dev %d - starting devices for calibration\n", __func__, idx); mutex_lock(&tfa98xx->dsp_lock); cal_profile = tfa_cont_get_cal_profile(tfa98xx->tfa); if (cal_profile < 0) { pr_warn("[0x%x] no cal profile is defined!\n", tfa98xx->i2c->addr); /* use current profile if there's no cal profile */ cal_profile = tfa98xx->profile; } ret = tfa98xx_tfa_start(tfa98xx, cal_profile, tfa98xx->vstep); if (ret != tfa_error_ok) { pr_warn("[0x%x] failure in starting device for calibration! (err %d)\n", tfa98xx->i2c->addr, ret); cal_err |= ret; } tfa98xx->dsp_init = TFA98XX_DSP_INIT_DONE; tfa98xx_set_dsp_configured(tfa98xx); mutex_unlock(&tfa98xx->dsp_lock); } for (idx = 0; idx < ndev; idx++) { tfa = tfa98xx_get_tfa_device_from_index(idx); if (tfa == NULL) continue; if (tfa->vval_active) { pr_info("%s: dev %d - restoring MTP (0 -> %d)\n", __func__, idx, mtpex[idx]); ret = tfa_dev_mtp_set(tfa, TFA_MTP_EX, mtpex[idx]); if (ret) pr_info("restoring MTPEX failed (%d)\n", ret); mtpex[idx] = tfa_dev_mtp_get(tfa, TFA_MTP_EX); re25 = tfa_dev_mtp_get(tfa, TFA_MTP_RE25); pr_info("%s: dev %d - readback MTP (%d, %d)\n", __func__, idx, mtpex[idx], re25); } } pr_info("%s: restore flag for auto calibration (enabled -> %s)", __func__, (temp_calflag) ? "disabled" : "enabled"); for (idx = 0; idx < ndev; idx++) { tfa = tfa98xx_get_tfa_device_from_index(idx); if (tfa == NULL) continue; /* restore flag for auto calibration */ tfa->disable_auto_cal = temp_calflag; } if (cal_err) { pr_info("%s: calibration failed! (err %d)\n", __func__, cal_err); /* do not return error in case of V validation */ if (tfa98xx0->tfa->vval_active) return 0; } pr_info("%s: calibration started!\n", __func__); pr_info("%s: end\n", __func__); return 0; } enum tfa98xx_error tfa98xx_read_reference_temp(short *value) { struct power_supply *psy = NULL; union power_supply_propval prop_read = {0}; int ret = 0; /* get power supply of "battery" */ /* value is preserved with default when error happens */ psy = power_supply_get_by_name(REF_TEMP_DEVICE_NAME); if (!psy) { pr_err("%s: failed to get power supply\n", __func__); return TFA98XX_ERROR_FAIL; } ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_TEMP, &prop_read); if (ret) { pr_err("%s: failed to get temp property\n", __func__); if (psy) power_supply_put(psy); return TFA98XX_ERROR_FAIL; } *value = (short)(prop_read.intval / 10); /* in degC */ pr_info("%s: read temp (%d) from %s\n", __func__, *value, REF_TEMP_DEVICE_NAME); if (psy) power_supply_put(psy); return TFA98XX_ERROR_OK; } static void tfa98xx_set_dsp_configured(struct tfa98xx *tfa98xx) { int is_configured; /* reset by default */ is_configured = tfa98xx->tfa->is_configured; switch (tfa98xx->dsp_init) { case TFA98XX_DSP_INIT_DONE: case TFA98XX_DSP_INIT_RECOVER: /* set working if already running */ is_configured = 1; break; case TFA98XX_DSP_INIT_INVALIDATED: /* preserve state except pstream off */ if (tfa98xx->pstream == 0) is_configured = 0; break; case TFA98XX_DSP_INIT_STOPPED: if (tfa98xx->tfa->is_probus_device) { /* preserve state except pstream off */ if (tfa98xx->pstream == 0) is_configured = 0; } else { /* reset for embedded DSP case */ is_configured = 0; } break; case TFA98XX_DSP_INIT_FAIL: is_configured = -1; break; case TFA98XX_DSP_INIT_PENDING: default: is_configured = 0; break; } pr_debug("[0x%x] dsp_init %d, is_configured %d\n", tfa98xx->i2c->addr, tfa98xx->dsp_init, is_configured); tfa98xx->tfa->is_configured = is_configured; } static int tfa98xx_get_vstep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); 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("%s: invalid profile %d (mixer_profile=%d, rate=%d)\n", __func__, 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] = tfa_cont_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_component *component = snd_soc_kcontrol_component(kcontrol); struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); 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("%s: invalid profile %d (mixer_profile=%d, rate=%d)\n", __func__, profile, mixer_profile, tfa98xx->rate); return -EINVAL; } /* wait until when DSP is ready for initialization */ if (tfa98xx->pstream == 0 && tfa98xx->samstream == 0) { pr_info("%s: tfa_start is suspended unless p/samstream is on\n", __func__); return 0; } 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 = tfa_cont_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; if (profile == tfa98xx->profile) { /* 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("Successfully changed vstep index!\n"); change = 1; } } /* Set DSP status as profile change may invalidate * current DSP configuration. Next stream start can * trigger a tfa_dev_start. */ tfa98xx->dsp_init = TFA98XX_DSP_INIT_INVALIDATED; tfa98xx_set_dsp_configured(tfa98xx); mutex_unlock(&tfa98xx->dsp_lock); } pr_debug("%d: vstep:%d, (control value: %d) - profile %d\n", tfa98xx->tfa->dev_idx, new_vstep, value, profile); } if (!change) { mutex_unlock(&tfa98xx_mutex); return change; } list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { mutex_lock(&tfa98xx->dsp_lock); if (tfa98xx->tfa->spkgain != -1) { pr_info("%s: set speaker gain 0x%x\n", __func__, tfa98xx->tfa->spkgain); TFA7x_SET_BF(tfa98xx->tfa, TDMSPKG, tfa98xx->tfa->spkgain); } pr_info("%s: UNMUTE dev %d\n", __func__, tfa98xx->tfa->dev_idx); 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_component *component = snd_soc_kcontrol_component(kcontrol); struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); int mixer_profile = tfa98xx_mixer_profile; int profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); if (profile < 0) { pr_err("%s: invalid profile %d (mixer_profile=%d, rate=%d)\n", __func__, 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, tfa_cont_get_max_vstep(tfa98xx->tfa, profile) - 1); pr_debug("vsteps count: %d [prof=%d]\n", tfa_cont_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_component *component = snd_soc_kcontrol_component(kcontrol); struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); int err = 0; int change = 0; int new_profile; int prof_idx, cur_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); cur_prof_idx = get_profile_id_for_sr(profile, tfa98xx->rate); if (prof_idx < 0 || cur_prof_idx < 0) { pr_err("%s: sample rate [%d] not supported for this mixer profile [%d -> %d]\n", __func__, tfa98xx->rate, profile, new_profile); return 0; } pr_info("%s: selected container profile [%d -> %d]\n", __func__, cur_prof_idx, prof_idx); pr_debug("%s: switch profile [%s -> %s]\n", __func__, _tfa_cont_profile_name(tfa98xx, cur_prof_idx), _tfa_cont_profile_name(tfa98xx, prof_idx)); /* update mixer profile */ tfa98xx_mixer_profile = new_profile; /* wait until when DSP is ready for initialization */ if (tfa98xx->pstream == 0 && tfa98xx->samstream == 0) { pr_info("%s: tfa_start is suspended unless p/samstream is on\n", __func__); return 0; } mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { int ready = 0; /* update 'real' profile (container profile) */ tfa98xx->profile = prof_idx; tfa98xx->vstep = tfa98xx->prof_vsteps[prof_idx]; mutex_lock(&tfa98xx->dsp_lock); /* Set ready by force, for selective channel control */ ready = 1; if (ready) { /* Also re-enables the interrupts */ pr_info("%s: trigger [dev %d - prof %d]\n", __func__, tfa98xx->tfa->dev_idx, prof_idx); 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; } } /* Set DSP status as profile change may invalidate * current DSP configuration. Next stream start can * trigger a tfa_dev_start. */ tfa98xx->dsp_init = TFA98XX_DSP_INIT_INVALIDATED; tfa98xx_set_dsp_configured(tfa98xx); mutex_unlock(&tfa98xx->dsp_lock); } if (!change) { mutex_unlock(&tfa98xx_mutex); return change; } list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { mutex_lock(&tfa98xx->dsp_lock); if (tfa98xx->tfa->spkgain != -1) { pr_info("%s: set speaker gain 0x%x\n", __func__, tfa98xx->tfa->spkgain); TFA7x_SET_BF(tfa98xx->tfa, TDMSPKG, tfa98xx->tfa->spkgain); } pr_info("%s: UNMUTE dev %d\n", __func__, tfa98xx->tfa->dev_idx); tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE, 0); mutex_unlock(&tfa98xx->dsp_lock); } mutex_unlock(&tfa98xx_mutex); return change; } /* 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 = strnchr(profile, strlen(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) { strlcpy(buf, bprof->basename, MAX_CONTROL_NAME); return 0; } } return TFA_ERROR; } /* 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) && (strncmp(bprof->basename, profile, len) == 0)) 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 TFA_ERROR; } return bprof->sr_rate_sup[idx]; } } /* profile not found */ return TFA_ERROR; } /* check if this profile is a calibration profile */ static int is_calibration_profile(char *profile) { if (strnstr(profile, ".cal", strlen(profile)) != 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; unsigned int sr0 = 0xff; static int sr_hit; list_for_each_entry(bprof, &profile_list, list) { if ((len == bprof->len) && (strncmp(bprof->basename, basename, len) == 0)) { /* 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 TFA_ERROR; } sr0 = (sr0 == 0xff) ? sr : sr0; /* default rate */ if (sr_converted == sr) { pr_debug("sr_converted: hits (%d)!\n", sr_converted); sr_hit = 1; } /* 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 TFA_ERROR; } /* 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); } } if (!sr_hit && sr0 != 0xff) { pr_info("sr_converted: use %d, as %d does not exist\n", sr0, sr_converted); sr_converted = sr0; } return 0; } 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; mutex_lock(&tfa98xx_mutex); uinfo->count = tfa98xx_device_count; mutex_unlock(&tfa98xx_mutex); 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; strlcpy(uinfo->value.enumerated.name, profile_name, MAX_CONTROL_NAME); return 0; } static int tfa98xx_info_device_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_device_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; struct tfa_device *tfa = NULL; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa = tfa98xx->tfa; if (tfa == NULL) continue; ucontrol->value.integer.value[tfa->dev_idx] = tfa->set_active; } mutex_unlock(&tfa98xx_mutex); return 0; } static int tfa98xx_set_device_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; struct tfa_device *tfa = NULL; enum tfa_error err; int dev; int request; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa = tfa98xx->tfa; if (tfa == NULL) continue; dev = tfa->dev_idx; request = ucontrol->value.integer.value[dev]; pr_info("%s: [%d] set active %d\n", __func__, dev, request); tfa->set_active = request; /* store for the next sessions */ /* exit if stream is not ready for immediate action */ if (tfa98xx->pstream == 0 && tfa98xx->samstream == 0) { pr_info("%s: [%d] store set active unless p/samstream is on\n", __func__, dev); continue; } switch (request) { case 0: /* deactivate immediately */ if (tfa->pause_state == 1) { pr_info("%s: [%d] already paused; no need to deactivate\n", __func__, dev); break; } pr_info("%s: [%d] deactivate channel\n", __func__, dev); cancel_delayed_work_sync(&tfa98xx->monitor_work); _tfa98xx_stop(tfa98xx); break; case 1: /* activate immediately */ if (tfa->pause_state == 0) { pr_info("%s: [%d] already resumed; no need to activate\n", __func__, dev); tfa_set_status_flag(tfa, TFA_SET_DEVICE, 1); break; } pr_info("%s: [%d] activate channel\n", __func__, dev); mutex_lock(&tfa98xx->dsp_lock); pr_info("%s: trigger [dev %d - prof %d]\n", __func__, dev, tfa98xx->profile); tfa_set_active_handle(tfa98xx->tfa, tfa98xx->profile); err = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); if (err) { pr_info("error in activation: %d\n", err); mutex_unlock(&tfa98xx->dsp_lock); break; } tfa98xx->dsp_init = TFA98XX_DSP_INIT_DONE; tfa98xx_set_dsp_configured(tfa98xx); if (tfa->spkgain != -1) { pr_info("%s: set speaker gain 0x%x\n", __func__, tfa->spkgain); TFA7x_SET_BF(tfa, TDMSPKG, tfa->spkgain); } pr_info("%s: UNMUTE dev %d\n", __func__, dev); tfa_dev_set_state(tfa, TFA_STATE_UNMUTE, 0); mutex_unlock(&tfa98xx->dsp_lock); break; default: pr_info("%s: [%d] wrong request\n", __func__, dev); break; } } /* reset counter */ tfa = tfa98xx_get_tfa_device_from_index(0); tfa_set_status_flag(tfa, TFA_SET_DEVICE, -1); mutex_unlock(&tfa98xx_mutex); return 1; } 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); _tfa98xx_stop(tfa98xx); } ucontrol->value.integer.value[i] = 0; } mutex_unlock(&tfa98xx_mutex); return 1; } static int tfa98xx_info_mute_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_mute_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; struct tfa_device *tfa = NULL; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa = tfa98xx->tfa; if (tfa == NULL) continue; ucontrol->value.integer.value[tfa->dev_idx] = tfa->mute_state; } mutex_unlock(&tfa98xx_mutex); return 0; } static int tfa98xx_set_mute_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; struct tfa_device *tfa = NULL; int dev; int request; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa = tfa98xx->tfa; if (tfa == NULL) continue; dev = tfa->dev_idx; request = ucontrol->value.integer.value[dev]; /* exit if stream is not ready for initialization */ if (tfa98xx->pstream == 0 && tfa98xx->samstream == 0) { pr_info("%s: [%d] only store request (%s), unless p/samstream is on\n", __func__, dev, (request == 1) ? "mute" : "unmute"); tfa->mute_state = request; continue; } switch (request) { case 0: /* unmute */ if (tfa->mute_state == 0) { pr_info("%s: [%d] already unmuted, skip the request\n", __func__, dev); break; } pr_info("%s: [%d] unmute channel\n", __func__, dev); mutex_lock(&tfa98xx->dsp_lock); tfa->mute_state = 0; tfa_run_unmute(tfa); mutex_unlock(&tfa98xx->dsp_lock); break; case 1: /* mute */ if (tfa->mute_state == 1) { pr_info("%s: [%d] already muted, skip the request\n", __func__, dev); break; } pr_info("%s: [%d] mute channel\n", __func__, dev); mutex_lock(&tfa98xx->dsp_lock); tfa->mute_state = 1; tfa_run_mute(tfa); mutex_unlock(&tfa98xx->dsp_lock); break; default: pr_info("%s: [%d] wrong request\n", __func__, dev); break; } } mutex_unlock(&tfa98xx_mutex); return 1; } static int tfa98xx_info_pause_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_pause_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; struct tfa_device *tfa = NULL; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa = tfa98xx->tfa; if (tfa == NULL) continue; ucontrol->value.integer.value[tfa->dev_idx] = tfa->pause_state; } mutex_unlock(&tfa98xx_mutex); return 0; } static int tfa98xx_set_pause_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; struct tfa_device *tfa = NULL; enum tfa_error err; int dev; int request; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa = tfa98xx->tfa; if (tfa == NULL) continue; dev = tfa->dev_idx; request = ucontrol->value.integer.value[dev]; switch (request) { case 0: /* resume */ if (tfa->pause_state == 0) { pr_info("%s: [%d] already resumed, skip the request\n", __func__, dev); tfa_set_status_flag(tfa, TFA_SET_DEVICE, 1); break; } /* exit if stream is not ready for initialization */ if (tfa98xx->pstream == 0 && tfa98xx->samstream == 0) { pr_info("%s: [%d] cannot resume unless p/samstream is on\n", __func__, dev); break; } pr_info("%s: [%d] resume channel\n", __func__, dev); mutex_lock(&tfa98xx->dsp_lock); pr_info("%s: trigger [dev %d - prof %d]\n", __func__, dev, tfa98xx->profile); tfa_set_active_handle(tfa98xx->tfa, tfa98xx->profile); err = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); if (err) { pr_info("error in activation: %d\n", err); mutex_unlock(&tfa98xx->dsp_lock); break; } tfa98xx->dsp_init = TFA98XX_DSP_INIT_DONE; tfa98xx_set_dsp_configured(tfa98xx); if (tfa->spkgain != -1) { pr_info("%s: set speaker gain 0x%x\n", __func__, tfa->spkgain); TFA7x_SET_BF(tfa, TDMSPKG, tfa->spkgain); } pr_info("%s: UNMUTE dev %d\n", __func__, dev); tfa_dev_set_state(tfa, TFA_STATE_UNMUTE, 0); mutex_unlock(&tfa98xx->dsp_lock); tfa->pause_state = 0; break; case 1: /* pause */ if (tfa->pause_state == 1) { pr_info("%s: [%d] already paused, skip the request\n", __func__, dev); break; } pr_info("%s: [%d] pause channel\n", __func__, dev); cancel_delayed_work_sync(&tfa98xx->monitor_work); _tfa98xx_stop(tfa98xx); tfa->pause_state = 1; break; default: pr_info("%s: [%d] wrong request\n", __func__, dev); break; } } /* reset counter */ tfa = tfa98xx_get_tfa_device_from_index(0); tfa_set_status_flag(tfa, TFA_SET_DEVICE, -1); mutex_unlock(&tfa98xx_mutex); return 1; } static int tfa98xx_info_spkgain(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 = 0x0; uinfo->value.integer.max = 0xf; return 0; } static int tfa98xx_get_spkgain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; struct tfa_device *tfa = NULL; int spkgain; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa = tfa98xx->tfa; if (tfa == NULL) continue; spkgain = tfa->spkgain; if (spkgain == -1) { spkgain = TFA7x_GET_BF(tfa, TDMSPKG); pr_info("%s: [%d] read current speaker gain 0x%x\n", __func__, tfa->dev_idx, spkgain); } ucontrol->value.integer.value[tfa->dev_idx] = spkgain; } mutex_unlock(&tfa98xx_mutex); return 0; } static int tfa98xx_set_spkgain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tfa98xx *tfa98xx; struct tfa_device *tfa = NULL; enum tfa98xx_error err; int dev; int cur_spkgain; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa = tfa98xx->tfa; if (tfa == NULL) continue; dev = tfa->dev_idx; tfa->spkgain = ucontrol->value.integer.value[dev]; cur_spkgain = TFA7x_GET_BF(tfa, TDMSPKG); pr_info("%s: [%d] set spekaer gain 0x%x (currently, 0x%x)\n", __func__, dev, tfa->spkgain, cur_spkgain); err = TFA7x_SET_BF(tfa, TDMSPKG, tfa->spkgain); if (err) pr_err("%s: [%d] failed to set speaker gain\n", __func__, dev); } 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; struct device *cdev; int ret; static int is_control_created; if (is_control_created) { pr_info("%s: Already created\n", __func__); return 0; } cdev = tfa98xx->component->dev; /* 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 */ nr_controls += 1; /* set active */ nr_controls += 1; /* set mute */ nr_controls += 1; /* set pause */ nr_controls += 1; /* set speaker gain */ 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 (tfa_cont_get_max_vstep(tfa98xx->tfa, prof)) nr_controls++; /* Playback Volume control */ } tfa98xx_controls = devm_kzalloc(cdev, 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(cdev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s Profile", tfa98xx->fw.name); pr_info("%s: Mixer Control Name = %s\n", __func__, 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; /* tfa98xx_controls[mix_index].private_value = profs; */ /* save number of profiles */ 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(cdev, 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 (with 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 (tfa_cont_get_max_vstep(tfa98xx->tfa, prof)) { name = devm_kzalloc(cdev, 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; tfa98xx_controls[mix_index].private_value = bprofile->item_id; /* save profile index */ 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 */ if (id > 0) /* if any profile to be registered */ tfa98xx_mixer_profiles = id; else if (tfa98xx_mixer_profiles == 0) tfa98xx_mixer_profiles = nprof; /* set active device for the following sessions */ name = devm_kzalloc(cdev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s Active", 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_device_ctl; tfa98xx_controls[mix_index].get = tfa98xx_get_device_ctl; tfa98xx_controls[mix_index].put = tfa98xx_set_device_ctl; mix_index++; /* Create a mixer item for stop control on TFA1 */ name = devm_kzalloc(cdev, 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++; /* set mute / unmute by force */ name = devm_kzalloc(cdev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s Mute", 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_mute_ctl; tfa98xx_controls[mix_index].get = tfa98xx_get_mute_ctl; tfa98xx_controls[mix_index].put = tfa98xx_set_mute_ctl; mix_index++; /* set pause / resume by force */ name = devm_kzalloc(cdev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s Pause", 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_pause_ctl; tfa98xx_controls[mix_index].get = tfa98xx_get_pause_ctl; tfa98xx_controls[mix_index].put = tfa98xx_set_pause_ctl; mix_index++; /* set speaker gain by force */ name = devm_kzalloc(cdev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s Gain", 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_spkgain; tfa98xx_controls[mix_index].get = tfa98xx_get_spkgain; tfa98xx_controls[mix_index].put = tfa98xx_set_spkgain; mix_index++; if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) { name = devm_kzalloc(cdev, 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++; } ret = snd_soc_add_component_controls(tfa98xx->component, tfa98xx_controls, mix_index); if (!ret) is_control_created = 1; return ret; } 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], name[50] = {0}; int i; int i2cbus = i2c->adapter->nr; int addr = i2c->addr; if (dai_drv && num_dai > 0) for (i = 0; i < num_dai; i++) { memcpy(name, dai_drv[i].name, strlen(dai_drv[i].name)); snprintf(buf, 50, "%s-%d-%x", name, i2cbus, addr); dai_drv[i].name = tfa98xx_devm_kstrdup(dev, buf); pr_info("dai_drv[%d].name=%s\n", i, dai_drv[i].name); memcpy(name, dai_drv[i].playback.stream_name, strlen(dai_drv[i].playback.stream_name)); snprintf(buf, 50, "%s-%d-%x", name, i2cbus, addr); dai_drv[i].playback.stream_name = tfa98xx_devm_kstrdup(dev, buf); pr_info("dai_drv[%d].playback.stream_name=%s\n", i, dai_drv[i].playback.stream_name); memcpy(name, dai_drv[i].capture.stream_name, strlen(dai_drv[i].capture.stream_name)); snprintf(buf, 50, "%s-%d-%x", name, i2cbus, addr); dai_drv[i].capture.stream_name = tfa98xx_devm_kstrdup(dev, buf); pr_info("dai_drv[%d].capture.stream_name=%s\n", i, dai_drv[i].capture.stream_name); } /* 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)) { memcpy(name, widgets[i].sname, strlen(widgets[i].sname)); snprintf(buf, 50, "%s-%d-%x", name, i2cbus, addr); widgets[i].sname = tfa98xx_devm_kstrdup(dev, buf); pr_info("widgets[%d].sname=%s\n", i, widgets[i].sname); } } 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 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_stereo[] = { {"OUTR", NULL, "AIF IN"}, }; static void tfa98xx_add_widgets(struct tfa98xx *tfa98xx) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(tfa98xx->component); unsigned int num_dapm_widgets = ARRAY_SIZE(tfa98xx_dapm_widgets_common); struct snd_soc_dapm_widget *widgets; widgets = devm_kzalloc(tfa98xx->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->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)); snd_soc_dapm_ignore_suspend(dapm, "AIF IN"); snd_soc_dapm_ignore_suspend(dapm, "OUTL"); snd_soc_dapm_ignore_suspend(dapm, "AIF OUT"); snd_soc_dapm_ignore_suspend(dapm, "AEC Loopback"); 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)); snd_soc_dapm_ignore_suspend(dapm, "OUTR"); } } /* 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->dev, "WR reg=0x%02x, val=0x%04x %s\n", subaddress, value, ret < 0 ? "Error!!" : ""); if (tfa98xx_ftrace_regs) tfa98xx_trace_printk ("WR 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->dev, "RD reg=0x%02x, val=0x%04x %s\n", subaddress, *val, ret < 0 ? "Error!!" : ""); if (tfa98xx_ftrace_regs) tfa98xx_trace_printk ("RD 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 */ int tfa98xx_write_dsp(void *tfa, int num_bytes, const char *command_buffer) { return TFA98XX_ERROR_NOT_SUPPORTED; } /* * read external dsp message */ int tfa98xx_read_dsp(void *tfa, int num_bytes, unsigned char *result_buffer) { return TFA98XX_ERROR_NOT_SUPPORTED; } /* * write/read external dsp message */ int tfa98xx_writeread_dsp(void *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, }, }; reg_buf = (unsigned char *) kmalloc(sizeof(reg), GFP_DMA); /* GRP_KERNEL also works */ 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 ("RD-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->dev, "WR-RAW len=%d\n", len); if (tfa98xx_ftrace_regs) tfa98xx_trace_printk ("WR-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; } int tfa_ext_register(dsp_send_message_t tfa_send_message, dsp_read_message_t tfa_read_message, tfa_event_handler_t *tfa_event_handler) { struct tfa98xx *tfa98xx; int dirt = 0; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa98xx->tfa->ext_dsp = 1; tfa98xx->tfa->is_probus_device = 1; tfa98xx->tfa->is_cold = 1; if (tfa_send_message != NULL) { dirt |= 0x1; tfa98xx->tfa->dev_ops.dsp_msg = tfa_send_message; } if (tfa_read_message != NULL) { dirt |= 0x2; tfa98xx->tfa->dev_ops.dsp_msg_read = tfa_read_message; } } if (tfa_event_handler != NULL) tfa_event_handler = (tfa_event_handler_t *)tfa_ext_event_handler; if (dirt == 0x3) tfa_set_ipc_loaded(1); mutex_unlock(&tfa98xx_mutex); return 0; } int ipi_tfadsp_write(void *tfa, int length, const char *buf) { enum tfa98xx_error err = TFA98XX_ERROR_OK; int ret = 0; if (buf == NULL) { pr_err("%s: error with NULL buffer\n", __func__); return TFA98XX_ERROR_BAD_PARAMETER; } if (length >= 3) pr_debug("%s: [0]:0x%02x-[1]:0x%02x-[2]:0x%02x, length:%d\n", __func__, buf[0], buf[1], buf[2], length); ret = mtk_spk_send_ipi_buf_to_dsp((void *)buf, (uint32_t)length); if (ret != 0) { pr_err("%s: error in sending message to DSP (err %d)\n", __func__, ret); err = TFA98XX_ERROR_DSP_NOT_RUNNING; } return (int)err; } int ipi_tfadsp_read(void *tfa, int length, unsigned char *bytes) { enum tfa98xx_error err = TFA98XX_ERROR_OK; int ret = 0; uint32_t buf_len; if (bytes == NULL) { pr_err("%s: error with NULL buffer\n", __func__); return TFA98XX_ERROR_BAD_PARAMETER; } ret = mtk_spk_recv_ipi_buf_from_dsp((int8_t *)bytes, (int16_t)length, &buf_len); if (ret != 0) { pr_err("%s: error in receiving message to DSP (err %d)\n", __func__, ret); err = TFA98XX_ERROR_DSP_NOT_RUNNING; } if (length >= 3) pr_debug("%s: [0]:0x%02x-[1]:0x%02x-[2]:0x%02x, length:%d, buf_len:%d\n", __func__, bytes[0], bytes[1], bytes[2], length, buf_len); return (int)err; } int tfa_set_blackbox(int enable) { struct tfa98xx *tfa98xx; mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) tfa98xx->tfa->blackbox_enable = enable; mutex_unlock(&tfa98xx_mutex); return 0; } /* Interrupts management */ static void tfa98xx_interrupt_enable_tfa2(struct tfa98xx *tfa98xx, bool enable) { tfa98xx->istatus = 0; /* clear all the events before enabling */ tfa_irq_clear(tfa98xx->tfa, tfa98xx->tfa->irq_all); tfa_irq_ena(tfa98xx->tfa, tfa9878_irq_stotds, enable); tfa_irq_ena(tfa98xx->tfa, tfa9878_irq_stocpr, enable); tfa_irq_ena(tfa98xx->tfa, tfa9878_irq_stuvds, enable); tfa_irq_ena(tfa98xx->tfa, tfa9878_irq_stmanalarm, enable); } /* 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) { struct tfa_container *container; struct tfa98xx *tfa98xx = context; enum tfa_error tfa_err; int container_size; int ret; unsigned int value; mutex_lock(&probe_lock); if (tfa98xx->dsp_fw_state == TFA98XX_DSP_FW_OK) { pr_info("%s: Already loaded\n", __func__); mutex_unlock(&probe_lock); return; } tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; if (!cont) { pr_err("Failed to read %s\n", fw_name); mutex_unlock(&probe_lock); 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"); mutex_unlock(&probe_lock); 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"); mutex_unlock(&probe_lock); 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); mutex_unlock(&probe_lock); return; } /* TEMPORARY, until TFA device is probed before tfa_ext is called */ if (tfa98xx->tfa->is_probus_device) { tfa98xx->tfa->dev_ops.dsp_msg = (dsp_send_message_t)ipi_tfadsp_write; tfa98xx->tfa->dev_ops.dsp_msg_read = (dsp_read_message_t)ipi_tfadsp_read; tfa_set_ipc_loaded(1); } else { /* DSP solution: non-probus */ tfa98xx->tfa->dev_ops.dsp_msg = (dsp_send_message_t)tfa_dsp_msg_rpc; tfa98xx->tfa->dev_ops.dsp_msg_read = (dsp_read_message_t)tfa_dsp_msg_read_rpc; tfa_set_ipc_loaded(1); } /* Enable debug traces */ tfa98xx->tfa->verbose = trace_level & 1; /* prefix is the application name from the cnt */ tfa_cont_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; value = snd_soc_component_read32(tfa98xx->component, TFA98XX_KEY2_PROTECTED_MTP0); if (value != -1) { tfa98xx->calibrate_done = (value & TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK) ? 1 : 0; pr_info("[0x%x] calibrate_done = MTPEX (%d) 0x%04x\n", tfa98xx->i2c->addr, tfa98xx->calibrate_done, value); } else { pr_info("[0x%x] error in reading MTPEX\n", tfa98xx->i2c->addr); tfa98xx->calibrate_done = 0; } pr_debug("Firmware init complete\n"); /* allocate buffer_pool */ if (tfa98xx->tfa->dev_idx == 0) { int index = 0; pr_info("Allocate buffer_pool\n"); for (index = 0; index < POOL_MAX_INDEX; index++) tfa_buffer_pool(tfa98xx->tfa, index, buf_pool_size[index], POOL_ALLOC); } if (no_start != 0) { mutex_unlock(&probe_lock); return; } /* Only controls for main device */ /* for the first device */ if (tfa98xx->tfa->dev_idx == 0) tfa98xx_create_controls(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); tfa98xx_set_stream_state(tfa98xx->tfa, 0); ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); if (ret == TFA98XX_ERROR_NOT_SUPPORTED) { tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; } else { /* reset cold amp state */ if (tfa98xx->tfa->tfa_family == 2) TFA_SET_BF(tfa98xx->tfa, MANSCONF, 1); } tfa_set_status_flag(tfa98xx->tfa, TFA_SET_DEVICE, 0); mutex_unlock(&tfa98xx->dsp_lock); } tfa98xx_interrupt_enable(tfa98xx, true); mutex_unlock(&probe_lock); } static int tfa98xx_load_container(struct tfa98xx *tfa98xx) { int tries = 0, ret; mutex_lock(&probe_lock); tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_PENDING; mutex_unlock(&probe_lock); do { ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, fw_name, tfa98xx->dev, GFP_KERNEL, tfa98xx, tfa98xx_container_loaded); if (!ret) { /* expecting sysfs fallback mechanism */ pr_info("%s: dsp_fw_state %d (if done, %d)\n", __func__, tfa98xx->dsp_fw_state, TFA98XX_DSP_FW_OK); return ret; } /* wait until driver completes loading */ msleep_interruptible(20); if (tfa98xx->dsp_fw_state == TFA98XX_DSP_FW_OK) break; msleep_interruptible(80); tries++; } while (tries < TFA98XX_LOADFW_NTRIES && tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK); return ret; } static void tfa98xx_monitor(struct work_struct *work) { struct tfa98xx *tfa98xx; enum tfa98xx_error error = TFA98XX_ERROR_OK; int handle = -1, is_active = 0; unsigned int val; int ret; mutex_lock(&probe_lock); tfa98xx = container_of(work, struct tfa98xx, monitor_work.work); pr_info("%s: [%d] - profile = %d: %s\n", __func__, tfa98xx->tfa->dev_idx, tfa98xx->profile, _tfa_cont_profile_name(tfa98xx, tfa98xx->profile)); if (tfa98xx->tfa->active_count == -1) tfa_set_active_handle(tfa98xx->tfa, tfa98xx->profile); is_active = tfa_is_active_device(tfa98xx->tfa); if (is_active) { handle = tfa98xx->tfa->dev_idx; pr_info("%s: profile = %d, active handle [%s]: %d\n", __func__, tfa98xx->profile, tfa_cont_device_name(tfa98xx->tfa->cnt, handle), tfa98xx->tfa->active_handle); } else { goto tfa_monitor_exit; } /* Check for tap-detection - bypass monitor if it is active */ if (tfa98xx->input) goto tfa_monitor_exit; mutex_lock(&tfa98xx->dsp_lock); error = tfa7x_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; tfa98xx_set_dsp_configured(tfa98xx); pr_info("%s: dsp_init (direct) with device %d, profile %d\n", __func__, tfa98xx->tfa->dev_idx, tfa98xx->profile); tfa98xx_dsp_init(tfa98xx); } } /* for debugging */ mutex_lock(&tfa98xx->dsp_lock); ret = regmap_read(tfa98xx->regmap, TFA98XX_SYS_CONTROL0, &val); if (!ret) pr_debug("[%d] SYS_CONTROL0: 0x%04x\n", handle, val); ret = regmap_read(tfa98xx->regmap, TFA98XX_SYS_CONTROL1, &val); if (!ret) pr_debug("[%d] SYS_CONTROL1: 0x%04x\n", handle, val); ret = regmap_read(tfa98xx->regmap, TFA98XX_SYS_CONTROL2, &val); if (!ret) pr_debug("[%d] SYS_CONTROL2: 0x%04x\n", handle, val); ret = regmap_read(tfa98xx->regmap, TFA98XX_CLOCK_CONTROL, &val); if (!ret) pr_debug("[%d] CLOCK_CONTROL: 0x%04x\n", handle, val); ret = regmap_read(tfa98xx->regmap, TFA98XX_STATUS_FLAGS0, &val); if (!ret) pr_debug("[%d] STATUS_FLAG0: 0x%04x\n", handle, val); ret = regmap_read(tfa98xx->regmap, TFA98XX_STATUS_FLAGS1, &val); if (!ret) pr_debug("[%d] STATUS_FLAG1: 0x%04x\n", handle, val); ret = regmap_read(tfa98xx->regmap, TFA98XX_STATUS_FLAGS3, &val); if (!ret) pr_debug("[%d] STATUS_FLAG3: 0x%04x\n", handle, val); ret = regmap_read(tfa98xx->regmap, TFA98XX_STATUS_FLAGS4, &val); if (!ret) pr_debug("[%d] STATUS_FLAG4: 0x%04x\n", handle, val); ret = regmap_read(tfa98xx->regmap, TFA98XX_TDM_CONFIG0, &val); if (!ret) pr_debug("[%d] TDM_CONFIG0: 0x%04x\n", handle, val); mutex_unlock(&tfa98xx->dsp_lock); tfa_monitor_exit: pr_info("%s: exit\n", __func__); mutex_unlock(&probe_lock); if (!tfa98xx->tfa->verbose) return; if (tfa98xx_monitor_count != -1) if (++tfa98xx_monitor_count > MONITOR_COUNT_MAX) return; /* reschedule */ queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->monitor_work, 5 * HZ); } static void tfa98xx_dsp_init(struct tfa98xx *tfa98xx) { int ret; static bool failed; bool reschedule = false; bool sync = false; bool do_sync; int active_device_count = tfa98xx_device_count; 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); pr_info("%s: ...\n", __func__); tfa98xx->dsp_init = TFA98XX_DSP_INIT_PENDING; /* 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->dev, "Failed in starting device\n"); failed = true; } else if (ret != TFA98XX_ERROR_OK) { dev_err(tfa98xx->dev, "Failed in starting device (err %d; count %d)\n", ret, tfa98xx->init_count); failed = true; sync = true; /* unmute by force, even if it fails */ tfa98xx->init_count = 0; } else { sync = true; failed = false; /* Subsystem ready, tfa init complete */ tfa98xx->dsp_init = TFA98XX_DSP_INIT_DONE; dev_dbg(tfa98xx->dev, "tfa_dev_start succeeded! (%d)\n", tfa98xx->init_count); tfa98xx->init_count = 0; } mutex_unlock(&tfa98xx->dsp_lock); if (reschedule) { struct tfa98xx *ntfa98xx; failed = false; /* reschedule this init work for later */ list_for_each_entry(ntfa98xx, &tfa98xx_device_list, list) { ntfa98xx->init_count++; pr_info("%s: dsp_init (direct) with device %d, profile %d\n", __func__, ntfa98xx->tfa->dev_idx, ntfa98xx->profile); tfa98xx_dsp_init(ntfa98xx); } } if (!sync) return; if (tfa98xx->tfa->active_count == -1) tfa_set_active_handle(tfa98xx->tfa, tfa98xx->profile); /* check if all devices have started */ mutex_lock(&tfa98xx_mutex); active_device_count = tfa98xx->tfa->active_count; if (tfa98xx_sync_count < active_device_count) tfa98xx_sync_count++; do_sync = (tfa98xx_sync_count >= active_device_count); /* when all devices have started then unmute */ if (do_sync) { tfa98xx_sync_count = 0; list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { struct tfa_device *ntfa = tfa98xx->tfa; mutex_lock(&tfa98xx->dsp_lock); if (failed) tfa98xx->dsp_init = TFA98XX_DSP_INIT_FAIL; tfa98xx_set_dsp_configured(tfa98xx); mutex_unlock(&tfa98xx->dsp_lock); if (!tfa_is_active_device(ntfa)) continue; pr_info("%s: profile = %d, active handle [%s]: %d\n", __func__, tfa98xx->profile, tfa_cont_device_name(ntfa->cnt, ntfa->dev_idx), ntfa->active_handle); if (failed) { tfa_handle_damaged_speakers(ntfa); continue; } mutex_lock(&tfa98xx->dsp_lock); if (ntfa->spkgain != -1) { pr_info("%s: set speaker gain 0x%x\n", __func__, ntfa->spkgain); TFA7x_SET_BF(ntfa, TDMSPKG, ntfa->spkgain); } pr_info("%s: UNMUTE dev %d\n", __func__, ntfa->dev_idx); tfa_dev_set_state(ntfa, TFA_STATE_UNMUTE, 0); /* * start monitor thread to check IC status bit * periodically, and re-init IC to recover if * needed. */ tfa98xx_monitor_count = 0; queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->monitor_work, 1 * HZ); mutex_unlock(&tfa98xx->dsp_lock); } failed = false; } mutex_unlock(&tfa98xx_mutex); } static void tfa98xx_set_irq_status(struct tfa98xx *tfa98xx, int bit, int value, int flag) { int mask = 1 << (bit & 0x0f); tfa98xx->istatus &= ~mask; tfa98xx->istatus |= (flag & 0x1) << (bit & 0x0f); /* value: 0 (active high) / 1 (active low) */ tfa_irq_set_pol(tfa98xx->tfa, bit, (value == 0) ? 1 : 0); tfa_irq_clear(tfa98xx->tfa, bit); pr_info("%s: status 0x%04x on dev %d\n", __func__, tfa98xx->istatus, tfa98xx->tfa->dev_idx); } static void tfa98xx_interrupt(struct work_struct *work) { struct tfa98xx *tfa98xx0 = container_of(work, struct tfa98xx, interrupt_work.work); struct tfa98xx *tfa98xx; int irq_gpio = tfa98xx0->irq_gpio; int value = 0; pr_info("%s: triggered\n", __func__); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { if (irq_gpio != tfa98xx->irq_gpio) continue; pr_info("%s: status check on dev %d\n", __func__, tfa98xx->tfa->dev_idx); mutex_lock(&tfa98xx->dsp_lock); if (tfa_irq_get(tfa98xx->tfa, tfa9878_irq_stotds)) { /* clear at read */ value = TFA7x_GET_BF(tfa98xx->tfa, OTDS); pr_err("%s: OTP is %s!\n", __func__, (value == 0) ? "detected" : "restored"); tfa98xx_set_irq_status(tfa98xx, tfa9878_irq_stotds, 0, (value == 0) ? 1 : 0); } if (tfa_irq_get(tfa98xx->tfa, tfa9878_irq_stocpr)) { /* clear at read */ value = TFA7x_GET_BF(tfa98xx->tfa, OCDS); pr_err("%s: OCP is %s!\n", __func__, (value == 1) ? "detected" : "restored"); tfa98xx_set_irq_status(tfa98xx, tfa9878_irq_stocpr, 0, (value == 1) ? 1 : 0); } if (tfa_irq_get(tfa98xx->tfa, tfa9878_irq_stuvds)) { /* clear at read */ value = TFA7x_GET_BF(tfa98xx->tfa, UVDS); pr_err("%s: UVP is %s!\n", __func__, (value == 0) ? "detected" : "restored"); tfa98xx_set_irq_status(tfa98xx, tfa9878_irq_stuvds, 0, (value == 0) ? 1 : 0); } if (tfa_irq_get(tfa98xx->tfa, tfa9878_irq_stmanalarm)) { /* clear at read */ value = TFA7x_GET_BF(tfa98xx->tfa, MANALARM); pr_err("%s: Alarm state is %s!\n", __func__, (value == 1) ? "detected" : "restored"); tfa98xx_set_irq_status(tfa98xx, tfa9878_irq_stmanalarm, 0, (value == 1) ? 1 : 0); } mutex_unlock(&tfa98xx->dsp_lock); } /* unmask interrupts masked in IRQ handler */ tfa_irq_unmask(tfa98xx0->tfa); } static int tfa98xx_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); int idx = 0; int i = 0; u64 formats; int err; struct device *cdev; cdev = component->dev; /* * 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 0: formats = SNDRV_PCM_FMTBIT_S16_LE; break; case 1: formats = SNDRV_PCM_FMTBIT_S24_LE; break; case 2: formats = SNDRV_PCM_FMTBIT_S32_LE; break; default: formats = TFA98XX_FORMATS; 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(cdev, "Container file not loaded\n"); return -EINVAL; } tfa98xx->rate_constraint.list = &tfa98xx->rate_constraint_list[0]; tfa98xx->rate_constraint.count = 0; pr_info("%s: add all the supported rates: 0x%04x\n", __func__, TFA98XX_RATES); for (i = 0; i < (int)ARRAY_SIZE(index_to_rate); i++) { if ((1 << i) & TFA98XX_RATES) { tfa98xx->rate_constraint_list[idx++] = index_to_rate[i]; tfa98xx->rate_constraint.count += 1; } } pr_info("%s: setting rate constraint (%d)\n", __func__, idx); 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_component_get_drvdata(codec_dai->component); 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_component_get_drvdata(dai->component); struct snd_soc_component *component = dai->component; struct device *cdev; cdev = component->dev; pr_debug("fmt=0x%x\n", fmt); /* Supported mode: I2S, PDM */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_DSP_A: if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { dev_err(cdev, "Invalid Codec main mode\n"); return -EINVAL; } break; case SND_SOC_DAIFMT_PDM: break; default: dev_err(cdev, "Unsupported DAI format %d\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; } tfa98xx->audio_mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; return 0; } int tfa98xx_get_fssel(unsigned int rate) { int i; for (i = 0; i < (int)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_component *component = dai->component; struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); unsigned int rate; int prof_idx; int sample_size; int slot_size; /* Supported */ rate = params_rate(params); sample_size = snd_pcm_format_width(params_format(params)); slot_size = snd_pcm_format_physical_width(params_format(params)); pr_info("%s: requested rate: %d, sample size: %d, physical size: %d\n", __func__, rate, sample_size, slot_size); if (no_start != 0) return 0; pr_info("%s: forced to change rate: %d to %d\n", __func__, rate, sr_converted); rate = sr_converted; /* 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; pr_info("%s: tfa98xx_profile %d\n", __func__, tfa98xx->profile); /* 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_component *component = dai->component; struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); dev_dbg(tfa98xx->dev, "%s: state: %d (stream = %d)\n", __func__, mute, stream); if (no_start) { pr_debug("no_start parameter set no tfa_dev_start or tfa_dev_stop, returning\n"); return 0; } _tfa98xx_mute(tfa98xx, mute, stream); return 0; } static int _tfa98xx_mute(struct tfa98xx *tfa98xx, int mute, int stream) { if (mute) { /* stop DSP only when both playback and capture streams * are deactivated */ if (stream == SNDRV_PCM_STREAM_PLAYBACK) { if (tfa98xx->pstream == 0) { pr_debug("mute:%d [pstream duplicated]\n", mute); return 0; } tfa98xx->pstream = 0; } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { if (tfa98xx->cstream == 0) { pr_debug("mute:%d [cstream duplicated]\n", mute); return 0; } tfa98xx->cstream = 0; } mutex_lock(&tfa98xx->dsp_lock); pr_info("mute:%d [pstream %d, cstream %d, samstream %d]\n", mute, tfa98xx->pstream, tfa98xx->cstream, tfa98xx->samstream); if ((tfa98xx_count_active_stream(BIT_PSTREAM) == tfa98xx_device_count) && (tfa98xx_count_active_stream(BIT_CSTREAM) == tfa98xx_device_count)) /* at first mute of either */ if (tfa98xx->tfa->blackbox_enable && !tfa98xx->tfa->unset_log) { /* get logging once * before shutting down pstream */ pr_info("%s: get blackbox logging\n", __func__); tfa_update_log(); } tfa98xx->tfa->unset_log = 0; tfa98xx_set_stream_state(tfa98xx->tfa, (tfa98xx->pstream & BIT_PSTREAM) |((tfa98xx->cstream<<1) & BIT_CSTREAM) |((tfa98xx->samstream<<2) & BIT_SAMSTREAM)); mutex_unlock(&tfa98xx->dsp_lock); /* case: both p/cstream (either) and samstream are off * if (!(tfa98xx->pstream == 0 || tfa98xx->cstream == 0) * || (tfa98xx->samstream != 0)) { * pr_info("mute is suspended until playback/saam are off\n"); * return 0; * } */ /* wait until both main streams (pstream / samstream) are off */ if ((tfa98xx->pstream == 0) && (tfa98xx->samstream == 0)) { pr_info("mute is triggered\n"); } else { pr_info("mute is suspended when only cstream is off\n"); return 0; } mutex_lock(&tfa98xx_mutex); tfa98xx_sync_count = 0; mutex_unlock(&tfa98xx_mutex); cancel_delayed_work_sync(&tfa98xx->monitor_work); _tfa98xx_stop(tfa98xx); } else { if (stream == SNDRV_PCM_STREAM_PLAYBACK) tfa98xx->pstream = 1; else if (stream == SNDRV_PCM_STREAM_CAPTURE) tfa98xx->cstream = 1; mutex_lock(&tfa98xx->dsp_lock); pr_info("mute:%d [pstream %d, cstream %d, samstream %d]\n", mute, tfa98xx->pstream, tfa98xx->cstream, tfa98xx->samstream); tfa98xx_set_stream_state(tfa98xx->tfa, (tfa98xx->pstream & BIT_PSTREAM) |((tfa98xx->cstream<<1) & BIT_CSTREAM) |((tfa98xx->samstream<<2) & BIT_SAMSTREAM)); mutex_unlock(&tfa98xx->dsp_lock); if (tfa98xx->tfa->set_active == 0) { pr_info("%s: skip unmuting device %d, if it's forced to set inactive\n", __func__, tfa98xx->tfa->dev_idx); tfa98xx->tfa->unset_log = 1; return 0; } /* case: either p/cstream (both) or samstream is on * if ((tfa98xx->pstream != 0 && tfa98xx->cstream != 0) * || tfa98xx->samstream != 0) { */ /* wait until DSP is ready for initialization */ if (stream == SNDRV_PCM_STREAM_PLAYBACK || stream == SNDRV_PCM_STREAM_SAAM) { pr_info("unmute is triggered\n"); } else { pr_info("unmute is suspended when only cstream is on\n"); return 0; } pr_debug("%s: unmute with profile %d\n", __func__, tfa98xx->profile); /* check index if it needs dsp init only for main device */ /* Start DSP */ pr_info("%s: start tfa amp\n", __func__); pr_info("%s: dsp_init (direct) with device %d, profile %d\n", __func__, tfa98xx->tfa->dev_idx, tfa98xx->profile); tfa98xx_dsp_init(tfa98xx); } return 0; } static int _tfa98xx_stop(struct tfa98xx *tfa98xx) { 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; tfa98xx_set_dsp_configured(tfa98xx); mutex_unlock(&tfa98xx->dsp_lock); 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 = MAX_HANDLES, .rates = TFA98XX_RATES, .formats = TFA98XX_FORMATS, }, .capture = { .stream_name = "AIF Capture", .channels_min = 1, .channels_max = MAX_HANDLES, .rates = TFA98XX_RATES, .formats = TFA98XX_FORMATS, }, .ops = &tfa98xx_dai_ops, .symmetric_rates = 1, .symmetric_channels = 0, .symmetric_samplebits = 0, }, }; static int tfa98xx_probe(struct snd_soc_component *component) { struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); int ret = 0; struct device *cdev; cdev = component->dev; pr_debug("%s:\n", __func__); /* 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; tfa98xx->tfa->tfacal_wq = create_singlethread_workqueue("tfacal"); if (!tfa98xx->tfa->tfacal_wq) return -ENOMEM; INIT_DELAYED_WORK(&tfa98xx->monitor_work, tfa98xx_monitor); INIT_DELAYED_WORK(&tfa98xx->interrupt_work, tfa98xx_interrupt); tfa98xx->component = component; snd_soc_component_init_regmap(component, tfa98xx->regmap); ret = tfa98xx_load_container(tfa98xx); pr_debug("Container loading requested: %d\n", ret); tfa98xx_add_widgets(tfa98xx); dev_info(cdev, "tfa98xx codec registered (%s)", tfa98xx->fw.name); return ret; } static void tfa98xx_remove(struct snd_soc_component *component) { struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); pr_debug("%s:\n", __func__); if (tfa98xx->tfa == NULL) return; tfa98xx_interrupt_enable(tfa98xx, false); cancel_delayed_work_sync(&tfa98xx->interrupt_work); cancel_delayed_work_sync(&tfa98xx->monitor_work); if (tfa98xx->tfa98xx_wq) destroy_workqueue(tfa98xx->tfa98xx_wq); if (tfa98xx->tfa->tfacal_wq) destroy_workqueue(tfa98xx->tfa->tfacal_wq); /* deallocate buffer_pool */ if (tfa98xx->tfa->dev_idx == 0) { int index = 0; pr_info("Deallocate buffer_pool\n"); for (index = 0; index < POOL_MAX_INDEX; index++) tfa_buffer_pool(tfa98xx->tfa, index, 0, POOL_FREE); } } static const struct snd_soc_component_driver soc_component_dev_tfa98xx = { .probe = tfa98xx_probe, .remove = tfa98xx_remove, }; 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) { /* * 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((unsigned int)tfa98xx->reset_gpio, reset); msleep(TFA_RESET_DELAY); gpio_set_value_cansleep((unsigned int)tfa98xx->reset_gpio, !reset); msleep(TFA_RESET_DELAY); } 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"); else dev_info(dev, "IRQ GPIO: %d\n", tfa98xx->irq_gpio); ret = of_property_read_u32(np, "reset-polarity", &value); if (ret < 0) /* when it fails to read from device tree */ tfa98xx->reset_polarity = LOW; /* RSTN */ else tfa98xx->reset_polarity = (value == 0) ? LOW : HIGH; dev_info(dev, "reset-polarity:%d\n", tfa98xx->reset_polarity); return 0; } static int tfa98xx_parse_limit_cal_dt(struct device *dev, struct tfa98xx *tfa98xx, struct device_node *np) { u32 value; int err_lower, err_upper; err_lower = of_property_read_u32(np, "lower-limit-cal", &value); if ((err_lower < 0) || (value < MIN_CALIBRATION_DATA)) tfa98xx->tfa->lower_limit_cal = MIN_CALIBRATION_DATA; else tfa98xx->tfa->lower_limit_cal = value; pr_info("[0x%x] lower limit cal : %d\n", tfa98xx->i2c->addr, tfa98xx->tfa->lower_limit_cal); err_upper = of_property_read_u32(np, "upper-limit-cal", &value); if ((err_upper < 0) || (value > MAX_CALIBRATION_DATA)) tfa98xx->tfa->upper_limit_cal = MAX_CALIBRATION_DATA; else tfa98xx->tfa->upper_limit_cal = value; pr_info("[0x%x] upper limit cal : %d\n", tfa98xx->i2c->addr, tfa98xx->tfa->upper_limit_cal); return ((err_lower == 0 && err_upper == 0) ? 0 : -1); } static int tfa98xx_parse_dummy_cal_dt(struct device *dev, struct tfa98xx *tfa98xx, struct device_node *np) { u32 value; int err; err = of_property_read_u32(np, "dummy-cal", &value); if (err < 0) { tfa98xx->tfa->dummy_cal = DUMMY_CALIBRATION_DATA; return TFA_NOT_FOUND; } if (value < MIN_CALIBRATION_DATA) tfa98xx->tfa->dummy_cal = MIN_CALIBRATION_DATA; else if (value > MAX_CALIBRATION_DATA) tfa98xx->tfa->dummy_cal = MAX_CALIBRATION_DATA; else tfa98xx->tfa->dummy_cal = value; pr_info("[0x%x] dummy cal : %d\n", tfa98xx->i2c->addr, tfa98xx->tfa->dummy_cal); return 0; } static int tfa98xx_parse_inchannel_dt(struct device *dev, struct tfa98xx *tfa98xx, struct device_node *np) { u32 value; int err; err = of_property_read_u32(np, "inchannel", &value); if (err < 0) { tfa98xx->tfa->inchannel = -1; /* to use default INDEX_0/1 */ return TFA_NOT_FOUND; } if (value < 0 || value >= MAX_CHANNELS) tfa98xx->tfa->inchannel = -1; /* to use default INDEX_0/1 */ else tfa98xx->tfa->inchannel = value; pr_info("[0x%x] inchannel : %d\n", tfa98xx->i2c->addr, tfa98xx->tfa->inchannel); 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; } pr_info("i2c set reg: 0x%x\n", tfa98xx->reg); 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); size_t write_count = (count > 2) ? 2 : count; /* 16-bit */ u8 *data; int ret = 0; int retries = I2C_RETRIES; data = kmalloc(write_count + 1, GFP_KERNEL); if (data == NULL) { ret = -ENOMEM; pr_debug("can not allocate memory\n"); return ret; } data[0] = tfa98xx->reg; memcpy(&data[1], buf, write_count); pr_debug("i2c rw write: 0x%x (offset %d, write_count %d, count %d)\n", tfa98xx->reg, (int)off, (int)write_count, (int)count); retry: ret = i2c_master_send(tfa98xx->i2c, data, write_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); size_t read_count = (count > 2) ? 2 : count; /* 16-bit */ struct i2c_msg msgs[] = { { .addr = tfa98xx->i2c->addr, .flags = 0, .len = 1, .buf = &tfa98xx->reg, }, { .addr = tfa98xx->i2c->addr, .flags = I2C_M_RD, .len = read_count, .buf = buf, }, }; int ret; int retries = I2C_RETRIES; if (count >= PAGE_SIZE) { pr_info("%s: blocked anonymous read!\n", __func__); return 0; } pr_debug("i2c rw read: 0x%x (offset %d, read_count %d, count %d)\n", tfa98xx->reg, (int)off, (int)read_count, (int)count); memset(buf, 0, count); 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 : 0); } static ssize_t tfa98xx_calibrate_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); int mtp = 0, mtpex = 0; int count = 0; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } tfa98xx_check_calibration(tfa98xx); if (tfa98xx->calibrate_done) { pr_info("[0x%x] Calibration Success\n", tfa98xx->i2c->addr); count = snprintf(buf, PAGE_SIZE, "[0x%02x] Success\n", tfa98xx->i2c->addr); } else { pr_info("[0x%x] Calibration Fail\n", tfa98xx->i2c->addr); count = snprintf(buf, PAGE_SIZE, "[0x%02x] Fail\n", tfa98xx->i2c->addr); } mtp = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_RE25); mtpex = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX); pr_info("[0x%x] MTPEX: %d, MTP: %d mOhm\n", tfa98xx->i2c->addr, mtpex, mtp); return count; } static ssize_t tfa98xx_calibrate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); int ret = 0; static const char ref[] = "1"; /* "please calibrate now" */ if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } /* check string length, and account for eol */ if (count > sizeof(ref) + 1 || count < (sizeof(ref) - 1)) return -EINVAL; /* Compare string, excluding the trailing \0 and the potentials eol */ if (strncmp(buf, ref, sizeof(ref) - 1)) { pr_info("[0x%x] %s: calibration is triggered with %s!\n", tfa98xx->i2c->addr, __func__, buf); return -EINVAL; } ret = tfa98xx_run_calibration(tfa98xx); if (ret < 0) return ret; return count; } static ssize_t tfa98xx_mtpex_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); int count = 0, value; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } 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 access MTPEX: %d\n", tfa98xx->i2c->addr, value); return -EIO; } pr_debug("[0x%x] MTPEX : %d\n", tfa98xx->i2c->addr, value); count = snprintf(buf, PAGE_SIZE, "[0x%02x] MTPEX %d\n", tfa98xx->i2c->addr, value); return count; } static ssize_t tfa98xx_mtpex_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); enum tfa_error err; static const char ref[] = "0"; /* "please calibrate now" */ enum tfa98xx_error ret; u16 temp_val = DEFAULT_REF_TEMP; int idx, ndev; struct tfa_device *ntfa = NULL; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } /* check string length, and account for eol */ if (count > sizeof(ref) + 1 || count < (sizeof(ref) - 1)) return -EINVAL; /* Compare string, excluding the trailing \0 and the potentials eol */ if (strncmp(buf, ref, sizeof(ref) - 1)) { pr_info("[0x%x] Can only clear MTPEX (0 value expected)\n", tfa98xx->i2c->addr); return -EINVAL; } /* EXT_TEMP */ ret = tfa98xx_read_reference_temp(&temp_val); if (ret) pr_err("error in reading reference temp\n"); ndev = tfa98xx->tfa->dev_count; for (idx = 0; idx < ndev; idx++) { ntfa = tfa98xx_get_tfa_device_from_index(idx); if (ntfa == NULL) continue; tfa98xx_set_exttemp(ntfa, (short)temp_val); } mutex_lock(&tfa98xx->dsp_lock); err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_EX, 0); mutex_unlock(&tfa98xx->dsp_lock); if (err != tfa_error_ok) { pr_err("[0x%x] Unable to access MTPEX: err %d (suspended)\n", tfa98xx->i2c->addr, err); /* suspend until TFA98xx is active */ tfa98xx->tfa->reset_mtpex = 1; return -EIO; } pr_info("[0x%x] MTPEX < 0\n", tfa98xx->i2c->addr); return count; } static ssize_t tfa98xx_re25_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); int count = 0, mtpex, value; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } mutex_lock(&tfa98xx->dsp_lock); mtpex = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX); if (mtpex) value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_RE25); else value = 0; mutex_unlock(&tfa98xx->dsp_lock); if (value < 0) { pr_err("[0x%x] Unable to access MTP RE25: %d\n", tfa98xx->i2c->addr, value); return -EIO; } pr_debug("[0x%x] MTP : %d\n", tfa98xx->i2c->addr, value); count = snprintf(buf, PAGE_SIZE, "[0x%02x] Calibration data %d mOhm\n", tfa98xx->i2c->addr, value); return count; } static ssize_t tfa98xx_re25_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { /* to prevent attack to tfa98xx_re25_store */ return count; } static ssize_t tfa98xx_blackbox_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); int count = 0; int idx, ndev, offset, addr; enum tfa98xx_error err = TFA98XX_ERROR_OK; struct tfa_device *tfa0 = NULL; struct tfa_device *ntfa = NULL; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } ndev = tfa98xx->tfa->dev_count; if (ndev < 1) return -EINVAL; /* select main device */ tfa0 = tfa98xx_get_tfa_device_from_index(0); /* update current session if it's active */ if (tfa98xx_count_active_stream(BIT_PSTREAM) > 0) err = tfa_update_log(); pr_info("blackbox state: %d\n", tfa0->blackbox_enable); for (idx = 0; idx < ndev; idx++) { offset = idx * ID_BLACKBOX_MAX; ntfa = tfa98xx_get_tfa_device_from_index(idx); if (ntfa == NULL) continue; addr = ntfa->resp_address; count = snprintf(buf + strlen(buf), PAGE_SIZE, "[0x%02x] maxX %d um, maxT %d degC, countXmax %d, countTmax %d, maxX_keep %d um, maxT_keep %d degC\n", addr, tfa0->log_data[offset + ID_MAXX_LOG], tfa0->log_data[offset + ID_MAXT_LOG], tfa0->log_data[offset + ID_OVERXMAX_COUNT], tfa0->log_data[offset + ID_OVERTMAX_COUNT], tfa0->log_data[offset + ID_MAXX_KEEP_LOG], tfa0->log_data[offset + ID_MAXT_KEEP_LOG]); /* skip resetting; reset only by registered callback * memset(tfa0->log_data + offset, * 0, sizeof(int) * TFA_LOG_MAX_COUNT); */ } return count; } static ssize_t tfa98xx_blackbox_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); int enable = 0; int ret = 0; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } /* check string length, and account for eol */ if (count < 1) return -EINVAL; if (!strncmp(buf, "1", 1)) enable = 1; else if (!strncmp(buf, "0", 1)) enable = 0; else { pr_info("%s: blackbox is triggered with %s!\n", __func__, buf); return -EINVAL; } pr_info("%s: blackbox < %d\n", __func__, enable); ret = tfa_set_blackbox(enable); if (tfa98xx->tfa->is_configured > 0) { pr_info("%s: set blackbox directly\n", __func__); tfa98xx->tfa->individual_msg = 1; ret = tfa_configure_log(enable); if (ret < 0) return ret; } return count; } static ssize_t tfa98xx_gain_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); int count = 0; int spkgain, ampgain; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } mutex_lock(&tfa98xx->dsp_lock); spkgain = TFA7x_GET_BF(tfa98xx->tfa, TDMSPKG); ampgain = TFA7x_GET_BF(tfa98xx->tfa, AMPGAIN); mutex_unlock(&tfa98xx->dsp_lock); if (spkgain < 0 || ampgain < 0) { pr_err("[0x%x] Unable to access TDMSPKG / AMPGAIN: (%d, %d)\n", tfa98xx->i2c->addr, spkgain, ampgain); return -EIO; } pr_debug("[0x%x] TDMSPKG : %d, AMPGAIN : %d\n", tfa98xx->i2c->addr, spkgain, ampgain); count = snprintf(buf, PAGE_SIZE, "[0x%02x] TDMSPKG %d, AMAPGAIN %d\n", tfa98xx->i2c->addr, spkgain, ampgain); return count; } static ssize_t tfa98xx_gain_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { /* to prevent attack to tfa98xx_re25_store */ return count; } static ssize_t tfa98xx_autocal_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); struct tfa_device *tfa = NULL; int count = 0; tfa = tfa98xx->tfa; if (!tfa) return -ENODEV; if (tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } pr_debug("[0x%x] autocal : %s\n", tfa98xx->i2c->addr, (tfa->disable_auto_cal) ? "disabled" : "enabled"); count = snprintf(buf, PAGE_SIZE, "%s\n", (tfa->disable_auto_cal) ? "0 (disabled)" : "1 (enabled)"); return count; } static ssize_t tfa98xx_autocal_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct tfa98xx *tfa98xx = dev_get_drvdata(dev); struct tfa_device *tfa = NULL; int enable = 0; if (tfa98xx->tfa->tfa_family == 0) { pr_err("[0x%x] %s: system is not initialized: not probed yet!\n", tfa98xx->i2c->addr, __func__); return -EIO; } /* check string length, and account for eol */ if (count < 1) return -EINVAL; if (!strncmp(buf, "1", 1)) enable = 1; else if (!strncmp(buf, "0", 1)) enable = 0; else { pr_info("%s: autocal is triggered with %s!\n", __func__, buf); return -EINVAL; } pr_info("%s: autocal < %d\n", __func__, enable); mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { tfa = tfa98xx->tfa; if (tfa == NULL) continue; tfa->disable_auto_cal = (enable) ? 0 : 1; } mutex_unlock(&tfa98xx_mutex); return count; } static struct bin_attribute dev_attr_rw = { .attr = { .name = "rw", .mode = 0600, }, .size = 0, .read = tfa98xx_rw_read, .write = tfa98xx_rw_write, }; static struct bin_attribute dev_attr_reg = { .attr = { .name = "reg", .mode = 0200, }, .size = 0, .read = NULL, .write = tfa98xx_reg_write, }; static struct device_attribute dev_attr_calibrate = { .attr = { .name = "calibrate", .mode = 0600, }, .show = tfa98xx_calibrate_show, .store = tfa98xx_calibrate_store, }; static struct device_attribute dev_attr_mtpex = { .attr = { .name = "MTPEX", .mode = 0600, }, .show = tfa98xx_mtpex_show, .store = tfa98xx_mtpex_store, }; static struct device_attribute dev_attr_re25 = { .attr = { .name = "re25", .mode = 0600, }, .show = tfa98xx_re25_show, .store = tfa98xx_re25_store, }; static struct device_attribute dev_attr_blackbox = { .attr = { .name = "log", .mode = 0600, }, .show = tfa98xx_blackbox_show, .store = tfa98xx_blackbox_store, }; static struct device_attribute dev_attr_gain = { .attr = { .name = "gain", .mode = 0600, }, .show = tfa98xx_gain_show, .store = tfa98xx_gain_store, }; static struct device_attribute dev_attr_autocal = { .attr = { .name = "autocal", .mode = 0600, }, .show = tfa98xx_autocal_show, .store = tfa98xx_autocal_store, }; struct tfa_device *tfa98xx_get_tfa_device_from_index(int index) { struct tfa98xx *tfa98xx; struct tfa_device *ntfa = NULL; static struct tfa_device *tfadevset[MAX_HANDLES]; if (index < 0 || index >= MAX_HANDLES) return NULL; if (tfadevset[index] != NULL) return tfadevset[index]; list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { if (tfa98xx->tfa->dev_idx == index) { ntfa = tfa98xx->tfa; tfadevset[index] = ntfa; break; } } return ntfa; } EXPORT_SYMBOL(tfa98xx_get_tfa_device_from_index); struct tfa_device *tfa98xx_get_tfa_device_from_channel(int channel) { struct tfa98xx *tfa98xx; struct tfa_device *ntfa = NULL; static struct tfa_device *tfachnset[MAX_CHANNELS]; int nchannel = -1; if (channel < 0 || channel >= MAX_CHANNELS) return NULL; if (tfachnset[channel] != NULL) return tfachnset[channel]; list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { nchannel = tfa98xx_get_cnt_bitfield(tfa98xx->tfa, TFA7x_FAM(tfa98xx->tfa, TDMSPKS)); if (nchannel == channel) { ntfa = tfa98xx->tfa; tfachnset[channel] = ntfa; break; } } return ntfa; } EXPORT_SYMBOL(tfa98xx_get_tfa_device_from_channel); int tfa98xx_count_active_stream(int stream_flag) { struct tfa98xx *tfa98xx; int stream_counter = 0; list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { if (tfa98xx->tfa->stream_state & stream_flag) stream_counter++; } return stream_counter; } enum tfa98xx_error tfa_run_cal(int index, uint16_t *value) { struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(index); struct tfa98xx *tfa98xx; int ret = 0; int mtpex = 0; int tries = 0; if (!tfa) return TFA98XX_ERROR_NOT_OPEN; tfa98xx = (struct tfa98xx *)tfa->data; /* check if calibration already runs */ tfa_wait_until_calibration_done(tfa); ret = tfa98xx_run_calibration(tfa98xx); if (ret < 0) return TFA98XX_ERROR_FAIL; tfa_wait_until_calibration_done(tfa); if (value == NULL) return TFA98XX_ERROR_BAD_PARAMETER; while (tries < TFA98XX_API_REWRTIE_MTP_NTRIES) { msleep_interruptible(CAL_STATUS_INTERVAL); mtpex = tfa_dev_mtp_get(tfa, TFA_MTP_EX); if (mtpex != 0) { msleep_interruptible(CAL_STATUS_INTERVAL); break; } tries++; } mtpex = tfa_dev_mtp_get(tfa, TFA_MTP_EX); if (mtpex != 1) return TFA98XX_ERROR_FAIL; *value = tfa_dev_mtp_get(tfa, TFA_MTP_RE25); if ((int)*value < 0) { pr_info("%s: calibration data is not valid\n", __func__); *value = 0xffff; tfa->temp = 0xffff; return TFA98XX_ERROR_FAIL; } return TFA98XX_ERROR_OK; } EXPORT_SYMBOL(tfa_run_cal); enum tfa98xx_error tfa_get_cal_data(int index, uint16_t *value) { struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(index); int mtp = 0, mtpex = 0; if (!tfa) return TFA98XX_ERROR_NOT_OPEN; mtp = tfa_dev_mtp_get(tfa, TFA_MTP_RE25); mtpex = tfa_dev_mtp_get(tfa, TFA_MTP_EX); if (value == NULL) return TFA98XX_ERROR_BAD_PARAMETER; if (mtpex != 1) return TFA98XX_ERROR_FAIL; *value = mtp; if ((int)*value < 0) { pr_info("%s: calibration data is not valid\n", __func__); *value = 0xffff; tfa->temp = 0xffff; return TFA98XX_ERROR_FAIL; } return TFA98XX_ERROR_OK; } EXPORT_SYMBOL(tfa_get_cal_data); enum tfa98xx_error tfa_get_cal_data_channel(int channel, uint16_t *value) { int index = tfa_get_dev_idx_from_inchannel(channel); if (index < 0 || index >= MAX_HANDLES) return TFA98XX_ERROR_FAIL; return tfa_get_cal_data(index, value); } EXPORT_SYMBOL(tfa_get_cal_data_channel); enum tfa98xx_error tfa_get_cal_temp(int index, uint16_t *value) { struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(index); int mtpex = 0; if (!tfa) return TFA98XX_ERROR_NOT_OPEN; mtpex = tfa_dev_mtp_get(tfa, TFA_MTP_EX); if (value == NULL) return TFA98XX_ERROR_BAD_PARAMETER; if (mtpex != 1) return TFA98XX_ERROR_FAIL; *value = tfa->temp; if (*value == 0xffff) { pr_info("%s: calibration temperature is not valid\n", __func__); *value = tfa98xx_get_exttemp(tfa); pr_info("%s: calibration temperature is not valid\n", __func__); return TFA98XX_ERROR_FAIL; } return TFA98XX_ERROR_OK; } EXPORT_SYMBOL(tfa_get_cal_temp); enum tfa98xx_error tfa_get_cal_temp_channel(int channel, uint16_t *value) { int index = tfa_get_dev_idx_from_inchannel(channel); if (index < 0 || index >= MAX_HANDLES) return TFA98XX_ERROR_FAIL; return tfa_get_cal_temp(index, value); } EXPORT_SYMBOL(tfa_get_cal_temp_channel); int tfa98xx_set_blackbox(int enable) { enum tfa98xx_error ret = TFA98XX_ERROR_OK; struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(0); if (!tfa) return TFA98XX_ERROR_NOT_OPEN; if (tfa->tfa_family == 0) return TFA98XX_ERROR_NOT_OPEN; pr_info("%s: blackbox < %d\n", __func__, enable); ret = tfa_set_blackbox(enable); if (tfa->is_configured > 0) { pr_info("%s: set blackbox directly\n", __func__); tfa->individual_msg = 1; ret = tfa_configure_log(enable); } return ret; } EXPORT_SYMBOL(tfa98xx_set_blackbox); int tfa98xx_get_blackbox_data(int dev, int *data) { enum tfa98xx_error ret = TFA98XX_ERROR_OK; struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(0); int ndev = 0; int offset; if (!tfa) return TFA98XX_ERROR_NOT_OPEN; if (tfa->tfa_family == 0) return TFA98XX_ERROR_NOT_OPEN; ndev = tfa->dev_count; if (ndev < 1) return TFA98XX_ERROR_NOT_OPEN; if (dev < 0 || dev >= ndev) return TFA98XX_ERROR_BAD_PARAMETER; pr_info("%s: blackbox state: %d\n", __func__, tfa->blackbox_enable); if (tfa->blackbox_enable == 0) { pr_info("%s: blackbox disabled - no update\n", __func__); return ret; } /* update current session if it's active */ if (tfa98xx_count_active_stream(BIT_PSTREAM) > 0 && tfa->is_configured > 0) { ret = tfa_update_log(); if (ret != TFA98XX_ERROR_OK) pr_info("%s: failure in updating current data\n", __func__); } offset = dev * ID_BLACKBOX_MAX; memcpy(data, tfa->log_data + offset, sizeof(int) * ID_BLACKBOX_MAX); /* reset after reading, except MAXX/T_KEEP_LOG */ memset(tfa->log_data + offset, 0, sizeof(int) * TFA_LOG_MAX_COUNT); return ret; } EXPORT_SYMBOL(tfa98xx_get_blackbox_data); int tfa98xx_get_blackbox_data_index(int dev, int index, int reset) { struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(0); int ndev = 0; enum tfa98xx_error ret = TFA98XX_ERROR_OK; int offset; int value = 0; if (!tfa) return -ENODEV; if (tfa->tfa_family == 0) return -ENODEV; if (index < 0 || index >= ID_BLACKBOX_MAX) return -EINVAL; ndev = tfa->dev_count; if (ndev < 1) return -EINVAL; if (dev < 0 || dev >= ndev) return -EINVAL; pr_info("%s: blackbox state: %d\n", __func__, tfa->blackbox_enable); if (tfa->blackbox_enable == 0) { pr_info("%s: blackbox disabled - no update\n", __func__); return -ENODEV; } /* update current session if it's active */ if (tfa98xx_count_active_stream(BIT_PSTREAM) > 0 && tfa->is_configured > 0) { ret = tfa_update_log(); if (ret != TFA98XX_ERROR_OK) pr_info("%s: failure in updating current data\n", __func__); } offset = dev * ID_BLACKBOX_MAX; value = tfa->log_data[offset + index]; /* reset after reading */ if (reset && (index < TFA_LOG_MAX_COUNT)) tfa->log_data[offset + index] = 0; return value; } EXPORT_SYMBOL(tfa98xx_get_blackbox_data_index); int tfa98xx_get_blackbox_data_index_channel(int channel, int index, int reset) { int dev = tfa_get_dev_idx_from_inchannel(channel); return tfa98xx_get_blackbox_data_index(dev, index, reset); } EXPORT_SYMBOL(tfa98xx_get_blackbox_data_index_channel); enum tfa98xx_error tfa_run_vval(int index, uint16_t *value) { struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(index); struct tfa_device *ntfa; struct tfa98xx *tfa98xx; int idx, ndev, ret = 0; int test_done = 0; if (!tfa) return TFA98XX_ERROR_NOT_OPEN; tfa98xx = (struct tfa98xx *)tfa->data; pr_info("%s: begin\n", __func__); ndev = tfa->dev_count; for (idx = 0; idx < ndev; idx++) { ntfa = tfa98xx_get_tfa_device_from_index(idx); if (ntfa == NULL) continue; /* set V validation */ ntfa->vval_active = 1; ntfa->vval_result = VVAL_UNTESTED; } /* check if calibration already runs */ test_done = tfa_wait_until_calibration_done(tfa); if (!test_done) { ret = tfa98xx_run_calibration(tfa98xx); if (ret < 0) { pr_info("%s: V validation failed\n", __func__); return TFA98XX_ERROR_FAIL; } tfa_wait_until_calibration_done(tfa); } if (value == NULL) return TFA98XX_ERROR_BAD_PARAMETER; *value = tfa->vval_result; if ((int)*value < 0) { pr_info("%s: V validation is not tested\n", __func__); *value = 0xffff; return TFA98XX_ERROR_OK; } for (idx = 0; idx < ndev; idx++) { ntfa = tfa98xx_get_tfa_device_from_index(idx); if (ntfa == NULL) continue; /* reset V validation */ ntfa->vval_active = 0; } pr_info("%s: end\n", __func__); return TFA98XX_ERROR_OK; } EXPORT_SYMBOL(tfa_run_vval); enum tfa98xx_error tfa_get_vval_data(int index, uint16_t *value) { struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(index); if (!tfa) return TFA98XX_ERROR_NOT_OPEN; if (value == NULL) return TFA98XX_ERROR_BAD_PARAMETER; *value = tfa->vval_result; if ((int)*value < 0) { pr_info("%s: V validation is not tested\n", __func__); *value = 0xffff; return TFA98XX_ERROR_OK; } return TFA98XX_ERROR_OK; } EXPORT_SYMBOL(tfa_get_vval_data); enum tfa98xx_error tfa_get_vval_data_channel(int channel, uint16_t *value) { int index = tfa_get_dev_idx_from_inchannel(channel); if (index < 0 || index >= MAX_HANDLES) return TFA98XX_ERROR_FAIL; return tfa_get_vval_data(index, value); } EXPORT_SYMBOL(tfa_get_vval_data_channel); int tfa_get_power_state(int index) { struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(index); int pm = 0; int state = 0, control = 0; if (tfa == NULL) return 0; /* unused device */ state = TFA7x_GET_BF(tfa, LP0); control = TFA7x_GET_BF(tfa, IPM); if ((control == 0x0 || control == 0x3) && (state == 0x1)) pm |= 0x2; /* idle power */ switch (tfa->rev & 0xff) { case 0x78: case 0x74: case 0x72: case 0x94: state = TFA7x_GET_BF(tfa, LP1); control = TFA7x_GET_BF(tfa, LPM1MODE); if ((control == 0x0 || control == 0x3) && (state == 0x1)) pm |= 0x1; /* low power */ break; default: /* neither TFA987x */ break; } state = TFA_GET_BF(tfa, PWDN); if (state == 1) pm |= 0x4; /* power down */ return pm; } int tfa98xx_update_spkt_data(int idx) { struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(0); struct tfa98xx *tfa98xx; int ret = 0; int value[MAX_HANDLES] = {0}; int i, ndev, data = 0; int pm = 0; if (tfa == NULL) return DEFAULT_REF_TEMP; /* unused device */ if (tfa->tfa_family == 0) return DEFAULT_REF_TEMP; if (tfa->active_handle > 0) { pr_info("%s: switched to active handle - %d\n", __func__, tfa->active_handle); tfa = tfa98xx_get_tfa_device_from_index(tfa->active_handle); if (tfa == NULL) return DEFAULT_REF_TEMP; if (tfa->tfa_family == 0) return DEFAULT_REF_TEMP; } ndev = tfa->dev_count; #if !defined(TFA_STEREO_NODE) if (ndev == 1 && idx > 0) idx = 0; /* use device 0 in mono, by force */ #endif if ((ndev < 1) || (idx < 0 || idx >= ndev)) return DEFAULT_REF_TEMP; if (tfa98xx_count_active_stream(BIT_PSTREAM) == 0) { pr_info("%s: skipped - tfadsp is not active!\n", __func__); return DEFAULT_REF_TEMP; } if (tfa->is_bypass) { pr_info("%s: skipped - tfadsp in bypass\n", __func__); return DEFAULT_REF_TEMP; } if (tfa->is_calibrating) { pr_info("%s: skipped - tfadsp is running calibraion!\n", __func__); return DEFAULT_REF_TEMP; } pm = tfa_get_power_state(idx); pr_info("%s: tfa_stc - dev %d - power state 0x%x\n", __func__, idx, pm); if (pm > 0) /* reset temperature in low power state */ return DEFAULT_REF_TEMP; if (tfa->is_configured <= 0) { pr_info("%s: skipped - tfadsp is not active\n", __func__); return DEFAULT_REF_TEMP; } pr_info("%s: tfa_stc - read tspkr for stc\n", __func__); tfa98xx = (struct tfa98xx *)tfa->data; mutex_lock(&tfa98xx->dsp_lock); ret = tfa_read_tspkr(tfa, value); mutex_unlock(&tfa98xx->dsp_lock); if (ret) { pr_info("%s: tfa_stc failed to read data from amplifier\n", __func__); value[idx] = DEFAULT_REF_TEMP; } if (value[idx] == 0xffff) { pr_info("%s: tfa_stc read wrong data from amplifier\n", __func__); } data = value[idx]; for (i = 0; i < ndev; i++) pr_debug("%s: data[%d]%s - %d\n", __func__, i, (idx == i) ? "*" : "", value[i]); return data; } EXPORT_SYMBOL(tfa98xx_update_spkt_data); int tfa98xx_update_spkt_data_channel(int channel) { int idx = tfa_get_dev_idx_from_inchannel(channel); return tfa98xx_update_spkt_data(idx); } EXPORT_SYMBOL(tfa98xx_update_spkt_data_channel); int tfa98xx_write_sknt_control(int idx, int value) { struct tfa_device *tfa = tfa98xx_get_tfa_device_from_index(0); struct tfa98xx *tfa98xx; int ret = 0; int pm = 0; int i, ndev, ready = 0; static int data[MAX_HANDLES]; static int update[MAX_HANDLES]; if (tfa == NULL) return -ENODEV; if (tfa->tfa_family == 0) return -ENODEV; if (tfa->active_handle > 0) { pr_info("%s: switched to active handle - %d\n", __func__, tfa->active_handle); tfa = tfa98xx_get_tfa_device_from_index(tfa->active_handle); if (tfa == NULL) return -ENODEV; if (tfa->tfa_family == 0) return -ENODEV; } ndev = tfa->dev_count; #if !defined(TFA_STEREO_NODE) if (ndev == 1 && idx > 0) idx = 0; /* use device 0 in mono, by force */ #endif if ((ndev < 1) || (idx < 0 || idx >= ndev)) return -EINVAL; if (tfa98xx_count_active_stream(BIT_PSTREAM) == 0) { pr_info("%s: skipped - no active stream!\n", __func__); goto tfa98xx_write_sknt_control_exit; } if (tfa->is_bypass) { pr_info("%s: skipped - tfadsp in bypass\n", __func__); goto tfa98xx_write_sknt_control_exit; } if (tfa->is_calibrating) { pr_info("%s: skipped - tfadsp is running calibraion!\n", __func__); goto tfa98xx_write_sknt_control_exit; } if (tfa->is_configured <= 0) { pr_info("%s: skipped - tfadsp is not active\n", __func__); goto tfa98xx_write_sknt_control_exit; } pm = tfa_get_power_state(idx); if (pm & 0x4) { /* skip if device is powered down */ pr_info("%s: tfa_stc - skip dev %d - power state 0x%x\n", __func__, idx, pm); return ret; } pr_info("%s: tfa_stc - dev %d - set surface temperature (%d)\n", __func__, idx, value); if (update[idx]) pr_debug("%s: tfa_stc - dev %d - overwrite data\n", __func__, idx); data[idx] = value; update[idx] = 1; for (i = 0; i < ndev; i++) { pm = tfa_get_power_state(i); if (pm & 0x4) { /* count power down */ pr_info("%s: tfa_stc - dev %d: check power down\n", __func__, i); ready++; data[i] = DEFAULT_REF_TEMP; continue; } if (update[i] > 0) ready++; } if (ready < ndev) /* wait until all the active devices are ready */ return ret; pr_info("%s: tfa_stc - write volume for stc\n", __func__); tfa98xx = (struct tfa98xx *)tfa->data; mutex_lock(&tfa98xx->dsp_lock); tfa->individual_msg = 1; ret = tfa_write_volume(tfa, data); mutex_unlock(&tfa98xx->dsp_lock); if (ret) { pr_info("%s: tfa_stc failed to write data to amplifier\n", __func__); goto tfa98xx_write_sknt_control_exit; } for (i = 0; i < ndev; i++) pr_debug("%s: data[%d]%s - %d\n", __func__, i, (update[i]) ? "*" : "", data[i]); tfa98xx_write_sknt_control_exit: pr_info("%s: tfa_stc - reset update flags\n", __func__); memset(update, 0, ndev * sizeof(int)); return ret; } EXPORT_SYMBOL(tfa98xx_write_sknt_control); int tfa98xx_write_sknt_control_channel(int channel, int value) { int idx = tfa_get_dev_idx_from_inchannel(channel); return tfa98xx_write_sknt_control(idx, value); } EXPORT_SYMBOL(tfa98xx_write_sknt_control_channel); 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("%s: start probing\n", __func__); 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 = gpio_request_one((unsigned int)tfa98xx->reset_gpio, GPIOF_OUT_INIT_HIGH, "TFA98XX_RSTN"); /* RSTN */ if (ret) return ret; } if (gpio_is_valid(tfa98xx->irq_gpio)) { ret = gpio_request_one((unsigned int)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, TFA98XX_DEVICE_REVISION, ®); 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; if (np) { ret = tfa98xx_parse_limit_cal_dt(&i2c->dev, tfa98xx, np); if (ret) { dev_err(&i2c->dev, "Failed to parse DT node for cal range\n"); /* set default range instead */ } ret = tfa98xx_parse_dummy_cal_dt(&i2c->dev, tfa98xx, np); if (ret) { dev_err(&i2c->dev, "Failed to parse DT node for dummy value for calibration\n"); /* set default value instead */ } ret = tfa98xx_parse_inchannel_dt(&i2c->dev, tfa98xx, np); if (ret) { dev_err(&i2c->dev, "Failed to parse DT node for inchannel\n"); /* set default value instead */ } } /* Modify the stream names, by appending the i2c device address. * This is used with multicodec, in order to discriminate 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_component(&i2c->dev, &soc_component_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((unsigned int)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((unsigned int)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; } #if defined(CONFIG_DEBUG_FS) if (no_start == 0) tfa98xx_debug_init(tfa98xx, i2c); #endif /* Register the sysfs files for climax backdoor access */ ret = sysfs_create_bin_file(&i2c->dev.kobj, &dev_attr_rw); if (ret) dev_info(&i2c->dev, "error creating sysfs node, rw\n"); ret = sysfs_create_bin_file(&i2c->dev.kobj, &dev_attr_reg); if (ret) dev_info(&i2c->dev, "error creating sysfs node, reg\n"); ret = device_create_file(&i2c->dev, &dev_attr_calibrate); if (ret) dev_info(&i2c->dev, "error creating sysfs node, calibrate\n"); ret = device_create_file(&i2c->dev, &dev_attr_mtpex); if (ret) dev_info(&i2c->dev, "error creating sysfs node, MTPEX\n"); ret = device_create_file(&i2c->dev, &dev_attr_re25); if (ret) dev_info(&i2c->dev, "error creating sysfs node, re25\n"); ret = device_create_file(&i2c->dev, &dev_attr_blackbox); if (ret) dev_info(&i2c->dev, "error creating sysfs node, log\n"); ret = device_create_file(&i2c->dev, &dev_attr_gain); if (ret) dev_info(&i2c->dev, "error creating sysfs node, gain\n"); ret = device_create_file(&i2c->dev, &dev_attr_autocal); if (ret) dev_info(&i2c->dev, "error creating sysfs node, autocal\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); /* stack */ mutex_unlock(&tfa98xx_mutex); return 0; } 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); sysfs_remove_bin_file(&i2c->dev.kobj, &dev_attr_reg); sysfs_remove_bin_file(&i2c->dev.kobj, &dev_attr_rw); #if defined(CONFIG_DEBUG_FS) tfa98xx_debug_remove(tfa98xx); #endif snd_soc_unregister_component(&i2c->dev); if (gpio_is_valid(tfa98xx->irq_gpio)) gpio_free((unsigned int)tfa98xx->irq_gpio); if (gpio_is_valid(tfa98xx->reset_gpio)) gpio_free((unsigned int)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; } #if 0 static const struct i2c_device_id tfa98xx_i2c_id[] = { {"tfa98xx", 0}, {} }; MODULE_DEVICE_TABLE(i2c, tfa98xx_i2c_id); #endif #ifdef CONFIG_OF static const struct of_device_id tfa98xx_dt_match[] = { {.compatible = "tfa,tfa98xx"}, {.compatible = "tfa,tfa9872"}, {.compatible = "tfa,tfa9874"}, {.compatible = "tfa,tfa9878"}, {.compatible = "tfa,tfa9888"}, {.compatible = "tfa,tfa9890"}, {.compatible = "tfa,tfa9891"}, {.compatible = "tfa,tfa9894"}, {.compatible = "tfa,tfa9895"}, {.compatible = "tfa,tfa9896"}, {.compatible = "tfa,tfa9897"}, {.compatible = "tfa,tfa9912"}, {}, }; #endif #if 0 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, }; #endif 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; } #if 0 ret = i2c_add_driver(&tfa98xx_i2c_driver); #endif return ret; } module_init(tfa98xx_i2c_init); static void __exit tfa98xx_i2c_exit(void) { #if 0 i2c_del_driver(&tfa98xx_i2c_driver); #endif kmem_cache_destroy(tfa98xx_cache); } module_exit(tfa98xx_i2c_exit); MODULE_DESCRIPTION("ASoC TFA98XX driver"); MODULE_LICENSE("GPL");