162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * drivers/mfd/si476x-cmd.c -- Subroutines implementing command 462306a36Sopenharmony_ci * protocol of si476x series of chips 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2012 Innovative Converged Devices(ICD) 762306a36Sopenharmony_ci * Copyright (C) 2013 Andrey Smirnov 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Author: Andrey Smirnov <andrew.smirnov@gmail.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/completion.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/atomic.h> 1662306a36Sopenharmony_ci#include <linux/i2c.h> 1762306a36Sopenharmony_ci#include <linux/device.h> 1862306a36Sopenharmony_ci#include <linux/gpio.h> 1962306a36Sopenharmony_ci#include <linux/videodev2.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/mfd/si476x-core.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <asm/unaligned.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define msb(x) ((u8)((u16) x >> 8)) 2662306a36Sopenharmony_ci#define lsb(x) ((u8)((u16) x & 0x00FF)) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define CMD_POWER_UP 0x01 3162306a36Sopenharmony_ci#define CMD_POWER_UP_A10_NRESP 1 3262306a36Sopenharmony_ci#define CMD_POWER_UP_A10_NARGS 5 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define CMD_POWER_UP_A20_NRESP 1 3562306a36Sopenharmony_ci#define CMD_POWER_UP_A20_NARGS 5 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define POWER_UP_DELAY_MS 110 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define CMD_POWER_DOWN 0x11 4062306a36Sopenharmony_ci#define CMD_POWER_DOWN_A10_NRESP 1 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define CMD_POWER_DOWN_A20_NRESP 1 4362306a36Sopenharmony_ci#define CMD_POWER_DOWN_A20_NARGS 1 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define CMD_FUNC_INFO 0x12 4662306a36Sopenharmony_ci#define CMD_FUNC_INFO_NRESP 7 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define CMD_SET_PROPERTY 0x13 4962306a36Sopenharmony_ci#define CMD_SET_PROPERTY_NARGS 5 5062306a36Sopenharmony_ci#define CMD_SET_PROPERTY_NRESP 1 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define CMD_GET_PROPERTY 0x14 5362306a36Sopenharmony_ci#define CMD_GET_PROPERTY_NARGS 3 5462306a36Sopenharmony_ci#define CMD_GET_PROPERTY_NRESP 4 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define CMD_AGC_STATUS 0x17 5762306a36Sopenharmony_ci#define CMD_AGC_STATUS_NRESP_A10 2 5862306a36Sopenharmony_ci#define CMD_AGC_STATUS_NRESP_A20 6 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define PIN_CFG_BYTE(x) (0x7F & (x)) 6162306a36Sopenharmony_ci#define CMD_DIG_AUDIO_PIN_CFG 0x18 6262306a36Sopenharmony_ci#define CMD_DIG_AUDIO_PIN_CFG_NARGS 4 6362306a36Sopenharmony_ci#define CMD_DIG_AUDIO_PIN_CFG_NRESP 5 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define CMD_ZIF_PIN_CFG 0x19 6662306a36Sopenharmony_ci#define CMD_ZIF_PIN_CFG_NARGS 4 6762306a36Sopenharmony_ci#define CMD_ZIF_PIN_CFG_NRESP 5 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define CMD_IC_LINK_GPO_CTL_PIN_CFG 0x1A 7062306a36Sopenharmony_ci#define CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS 4 7162306a36Sopenharmony_ci#define CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP 5 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define CMD_ANA_AUDIO_PIN_CFG 0x1B 7462306a36Sopenharmony_ci#define CMD_ANA_AUDIO_PIN_CFG_NARGS 1 7562306a36Sopenharmony_ci#define CMD_ANA_AUDIO_PIN_CFG_NRESP 2 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define CMD_INTB_PIN_CFG 0x1C 7862306a36Sopenharmony_ci#define CMD_INTB_PIN_CFG_NARGS 2 7962306a36Sopenharmony_ci#define CMD_INTB_PIN_CFG_A10_NRESP 6 8062306a36Sopenharmony_ci#define CMD_INTB_PIN_CFG_A20_NRESP 3 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define CMD_FM_TUNE_FREQ 0x30 8362306a36Sopenharmony_ci#define CMD_FM_TUNE_FREQ_A10_NARGS 5 8462306a36Sopenharmony_ci#define CMD_FM_TUNE_FREQ_A20_NARGS 3 8562306a36Sopenharmony_ci#define CMD_FM_TUNE_FREQ_NRESP 1 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define CMD_FM_RSQ_STATUS 0x32 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define CMD_FM_RSQ_STATUS_A10_NARGS 1 9062306a36Sopenharmony_ci#define CMD_FM_RSQ_STATUS_A10_NRESP 17 9162306a36Sopenharmony_ci#define CMD_FM_RSQ_STATUS_A30_NARGS 1 9262306a36Sopenharmony_ci#define CMD_FM_RSQ_STATUS_A30_NRESP 23 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define CMD_FM_SEEK_START 0x31 9662306a36Sopenharmony_ci#define CMD_FM_SEEK_START_NARGS 1 9762306a36Sopenharmony_ci#define CMD_FM_SEEK_START_NRESP 1 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define CMD_FM_RDS_STATUS 0x36 10062306a36Sopenharmony_ci#define CMD_FM_RDS_STATUS_NARGS 1 10162306a36Sopenharmony_ci#define CMD_FM_RDS_STATUS_NRESP 16 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define CMD_FM_RDS_BLOCKCOUNT 0x37 10462306a36Sopenharmony_ci#define CMD_FM_RDS_BLOCKCOUNT_NARGS 1 10562306a36Sopenharmony_ci#define CMD_FM_RDS_BLOCKCOUNT_NRESP 8 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#define CMD_FM_PHASE_DIVERSITY 0x38 10862306a36Sopenharmony_ci#define CMD_FM_PHASE_DIVERSITY_NARGS 1 10962306a36Sopenharmony_ci#define CMD_FM_PHASE_DIVERSITY_NRESP 1 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define CMD_FM_PHASE_DIV_STATUS 0x39 11262306a36Sopenharmony_ci#define CMD_FM_PHASE_DIV_STATUS_NRESP 2 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define CMD_AM_TUNE_FREQ 0x40 11562306a36Sopenharmony_ci#define CMD_AM_TUNE_FREQ_NARGS 3 11662306a36Sopenharmony_ci#define CMD_AM_TUNE_FREQ_NRESP 1 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#define CMD_AM_RSQ_STATUS 0x42 11962306a36Sopenharmony_ci#define CMD_AM_RSQ_STATUS_NARGS 1 12062306a36Sopenharmony_ci#define CMD_AM_RSQ_STATUS_NRESP 13 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#define CMD_AM_SEEK_START 0x41 12362306a36Sopenharmony_ci#define CMD_AM_SEEK_START_NARGS 1 12462306a36Sopenharmony_ci#define CMD_AM_SEEK_START_NRESP 1 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define CMD_AM_ACF_STATUS 0x45 12862306a36Sopenharmony_ci#define CMD_AM_ACF_STATUS_NRESP 6 12962306a36Sopenharmony_ci#define CMD_AM_ACF_STATUS_NARGS 1 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#define CMD_FM_ACF_STATUS 0x35 13262306a36Sopenharmony_ci#define CMD_FM_ACF_STATUS_NRESP 8 13362306a36Sopenharmony_ci#define CMD_FM_ACF_STATUS_NARGS 1 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define CMD_MAX_ARGS_COUNT (10) 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cienum si476x_acf_status_report_bits { 13962306a36Sopenharmony_ci SI476X_ACF_BLEND_INT = (1 << 4), 14062306a36Sopenharmony_ci SI476X_ACF_HIBLEND_INT = (1 << 3), 14162306a36Sopenharmony_ci SI476X_ACF_HICUT_INT = (1 << 2), 14262306a36Sopenharmony_ci SI476X_ACF_CHBW_INT = (1 << 1), 14362306a36Sopenharmony_ci SI476X_ACF_SOFTMUTE_INT = (1 << 0), 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci SI476X_ACF_SMUTE = (1 << 0), 14662306a36Sopenharmony_ci SI476X_ACF_SMATTN = 0x1f, 14762306a36Sopenharmony_ci SI476X_ACF_PILOT = (1 << 7), 14862306a36Sopenharmony_ci SI476X_ACF_STBLEND = ~SI476X_ACF_PILOT, 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cienum si476x_agc_status_report_bits { 15262306a36Sopenharmony_ci SI476X_AGC_MXHI = (1 << 5), 15362306a36Sopenharmony_ci SI476X_AGC_MXLO = (1 << 4), 15462306a36Sopenharmony_ci SI476X_AGC_LNAHI = (1 << 3), 15562306a36Sopenharmony_ci SI476X_AGC_LNALO = (1 << 2), 15662306a36Sopenharmony_ci}; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cienum si476x_errors { 15962306a36Sopenharmony_ci SI476X_ERR_BAD_COMMAND = 0x10, 16062306a36Sopenharmony_ci SI476X_ERR_BAD_ARG1 = 0x11, 16162306a36Sopenharmony_ci SI476X_ERR_BAD_ARG2 = 0x12, 16262306a36Sopenharmony_ci SI476X_ERR_BAD_ARG3 = 0x13, 16362306a36Sopenharmony_ci SI476X_ERR_BAD_ARG4 = 0x14, 16462306a36Sopenharmony_ci SI476X_ERR_BUSY = 0x18, 16562306a36Sopenharmony_ci SI476X_ERR_BAD_INTERNAL_MEMORY = 0x20, 16662306a36Sopenharmony_ci SI476X_ERR_BAD_PATCH = 0x30, 16762306a36Sopenharmony_ci SI476X_ERR_BAD_BOOT_MODE = 0x31, 16862306a36Sopenharmony_ci SI476X_ERR_BAD_PROPERTY = 0x40, 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic int si476x_core_parse_and_nag_about_error(struct si476x_core *core) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci int err; 17462306a36Sopenharmony_ci char *cause; 17562306a36Sopenharmony_ci u8 buffer[2]; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (core->revision != SI476X_REVISION_A10) { 17862306a36Sopenharmony_ci err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, 17962306a36Sopenharmony_ci buffer, sizeof(buffer)); 18062306a36Sopenharmony_ci if (err == sizeof(buffer)) { 18162306a36Sopenharmony_ci switch (buffer[1]) { 18262306a36Sopenharmony_ci case SI476X_ERR_BAD_COMMAND: 18362306a36Sopenharmony_ci cause = "Bad command"; 18462306a36Sopenharmony_ci err = -EINVAL; 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci case SI476X_ERR_BAD_ARG1: 18762306a36Sopenharmony_ci cause = "Bad argument #1"; 18862306a36Sopenharmony_ci err = -EINVAL; 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci case SI476X_ERR_BAD_ARG2: 19162306a36Sopenharmony_ci cause = "Bad argument #2"; 19262306a36Sopenharmony_ci err = -EINVAL; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci case SI476X_ERR_BAD_ARG3: 19562306a36Sopenharmony_ci cause = "Bad argument #3"; 19662306a36Sopenharmony_ci err = -EINVAL; 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci case SI476X_ERR_BAD_ARG4: 19962306a36Sopenharmony_ci cause = "Bad argument #4"; 20062306a36Sopenharmony_ci err = -EINVAL; 20162306a36Sopenharmony_ci break; 20262306a36Sopenharmony_ci case SI476X_ERR_BUSY: 20362306a36Sopenharmony_ci cause = "Chip is busy"; 20462306a36Sopenharmony_ci err = -EBUSY; 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci case SI476X_ERR_BAD_INTERNAL_MEMORY: 20762306a36Sopenharmony_ci cause = "Bad internal memory"; 20862306a36Sopenharmony_ci err = -EIO; 20962306a36Sopenharmony_ci break; 21062306a36Sopenharmony_ci case SI476X_ERR_BAD_PATCH: 21162306a36Sopenharmony_ci cause = "Bad patch"; 21262306a36Sopenharmony_ci err = -EINVAL; 21362306a36Sopenharmony_ci break; 21462306a36Sopenharmony_ci case SI476X_ERR_BAD_BOOT_MODE: 21562306a36Sopenharmony_ci cause = "Bad boot mode"; 21662306a36Sopenharmony_ci err = -EINVAL; 21762306a36Sopenharmony_ci break; 21862306a36Sopenharmony_ci case SI476X_ERR_BAD_PROPERTY: 21962306a36Sopenharmony_ci cause = "Bad property"; 22062306a36Sopenharmony_ci err = -EINVAL; 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci default: 22362306a36Sopenharmony_ci cause = "Unknown"; 22462306a36Sopenharmony_ci err = -EIO; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci dev_err(&core->client->dev, 22862306a36Sopenharmony_ci "[Chip error status]: %s\n", cause); 22962306a36Sopenharmony_ci } else { 23062306a36Sopenharmony_ci dev_err(&core->client->dev, 23162306a36Sopenharmony_ci "Failed to fetch error code\n"); 23262306a36Sopenharmony_ci err = (err >= 0) ? -EIO : err; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci } else { 23562306a36Sopenharmony_ci err = -EIO; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return err; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci/** 24262306a36Sopenharmony_ci * si476x_core_send_command() - sends a command to si476x and waits its 24362306a36Sopenharmony_ci * response 24462306a36Sopenharmony_ci * @core: si476x_device structure for the device we are 24562306a36Sopenharmony_ci * communicating with 24662306a36Sopenharmony_ci * @command: command id 24762306a36Sopenharmony_ci * @args: command arguments we are sending 24862306a36Sopenharmony_ci * @argn: actual size of @args 24962306a36Sopenharmony_ci * @resp: buffer to place the expected response from the device 25062306a36Sopenharmony_ci * @respn: actual size of @resp 25162306a36Sopenharmony_ci * @usecs: amount of time to wait before reading the response (in 25262306a36Sopenharmony_ci * usecs) 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * Function returns 0 on success and negative error code on 25562306a36Sopenharmony_ci * failure 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_cistatic int si476x_core_send_command(struct si476x_core *core, 25862306a36Sopenharmony_ci const u8 command, 25962306a36Sopenharmony_ci const u8 args[], 26062306a36Sopenharmony_ci const int argn, 26162306a36Sopenharmony_ci u8 resp[], 26262306a36Sopenharmony_ci const int respn, 26362306a36Sopenharmony_ci const int usecs) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct i2c_client *client = core->client; 26662306a36Sopenharmony_ci int err; 26762306a36Sopenharmony_ci u8 data[CMD_MAX_ARGS_COUNT + 1]; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (argn > CMD_MAX_ARGS_COUNT) { 27062306a36Sopenharmony_ci err = -ENOMEM; 27162306a36Sopenharmony_ci goto exit; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (!client->adapter) { 27562306a36Sopenharmony_ci err = -ENODEV; 27662306a36Sopenharmony_ci goto exit; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* First send the command and its arguments */ 28062306a36Sopenharmony_ci data[0] = command; 28162306a36Sopenharmony_ci memcpy(&data[1], args, argn); 28262306a36Sopenharmony_ci dev_dbg(&client->dev, "Command:\n %*ph\n", argn + 1, data); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci err = si476x_core_i2c_xfer(core, SI476X_I2C_SEND, 28562306a36Sopenharmony_ci (char *) data, argn + 1); 28662306a36Sopenharmony_ci if (err != argn + 1) { 28762306a36Sopenharmony_ci dev_err(&core->client->dev, 28862306a36Sopenharmony_ci "Error while sending command 0x%02x\n", 28962306a36Sopenharmony_ci command); 29062306a36Sopenharmony_ci err = (err >= 0) ? -EIO : err; 29162306a36Sopenharmony_ci goto exit; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci /* Set CTS to zero only after the command is send to avoid 29462306a36Sopenharmony_ci * possible racing conditions when working in polling mode */ 29562306a36Sopenharmony_ci atomic_set(&core->cts, 0); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* if (unlikely(command == CMD_POWER_DOWN) */ 29862306a36Sopenharmony_ci if (!wait_event_timeout(core->command, 29962306a36Sopenharmony_ci atomic_read(&core->cts), 30062306a36Sopenharmony_ci usecs_to_jiffies(usecs) + 1)) 30162306a36Sopenharmony_ci dev_warn(&core->client->dev, 30262306a36Sopenharmony_ci "(%s) [CMD 0x%02x] Answer timeout.\n", 30362306a36Sopenharmony_ci __func__, command); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* 30662306a36Sopenharmony_ci When working in polling mode, for some reason the tuner will 30762306a36Sopenharmony_ci report CTS bit as being set in the first status byte read, 30862306a36Sopenharmony_ci but all the consequtive ones will return zeros until the 30962306a36Sopenharmony_ci tuner is actually completed the POWER_UP command. To 31062306a36Sopenharmony_ci workaround that we wait for second CTS to be reported 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci if (unlikely(!core->client->irq && command == CMD_POWER_UP)) { 31362306a36Sopenharmony_ci if (!wait_event_timeout(core->command, 31462306a36Sopenharmony_ci atomic_read(&core->cts), 31562306a36Sopenharmony_ci usecs_to_jiffies(usecs) + 1)) 31662306a36Sopenharmony_ci dev_warn(&core->client->dev, 31762306a36Sopenharmony_ci "(%s) Power up took too much time.\n", 31862306a36Sopenharmony_ci __func__); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci /* Then get the response */ 32262306a36Sopenharmony_ci err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, resp, respn); 32362306a36Sopenharmony_ci if (err != respn) { 32462306a36Sopenharmony_ci dev_err(&core->client->dev, 32562306a36Sopenharmony_ci "Error while reading response for command 0x%02x\n", 32662306a36Sopenharmony_ci command); 32762306a36Sopenharmony_ci err = (err >= 0) ? -EIO : err; 32862306a36Sopenharmony_ci goto exit; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci dev_dbg(&client->dev, "Response:\n %*ph\n", respn, resp); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci err = 0; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (resp[0] & SI476X_ERR) { 33562306a36Sopenharmony_ci dev_err(&core->client->dev, 33662306a36Sopenharmony_ci "[CMD 0x%02x] Chip set error flag\n", command); 33762306a36Sopenharmony_ci err = si476x_core_parse_and_nag_about_error(core); 33862306a36Sopenharmony_ci goto exit; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!(resp[0] & SI476X_CTS)) 34262306a36Sopenharmony_ci err = -EBUSY; 34362306a36Sopenharmony_ciexit: 34462306a36Sopenharmony_ci return err; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int si476x_cmd_clear_stc(struct si476x_core *core) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci int err; 35062306a36Sopenharmony_ci struct si476x_rsq_status_args args = { 35162306a36Sopenharmony_ci .primary = false, 35262306a36Sopenharmony_ci .rsqack = false, 35362306a36Sopenharmony_ci .attune = false, 35462306a36Sopenharmony_ci .cancel = false, 35562306a36Sopenharmony_ci .stcack = true, 35662306a36Sopenharmony_ci }; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci switch (core->power_up_parameters.func) { 35962306a36Sopenharmony_ci case SI476X_FUNC_FM_RECEIVER: 36062306a36Sopenharmony_ci err = si476x_core_cmd_fm_rsq_status(core, &args, NULL); 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci case SI476X_FUNC_AM_RECEIVER: 36362306a36Sopenharmony_ci err = si476x_core_cmd_am_rsq_status(core, &args, NULL); 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci default: 36662306a36Sopenharmony_ci err = -EINVAL; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return err; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int si476x_cmd_tune_seek_freq(struct si476x_core *core, 37362306a36Sopenharmony_ci uint8_t cmd, 37462306a36Sopenharmony_ci const uint8_t args[], size_t argn, 37562306a36Sopenharmony_ci uint8_t *resp, size_t respn) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci int err; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci atomic_set(&core->stc, 0); 38162306a36Sopenharmony_ci err = si476x_core_send_command(core, cmd, args, argn, resp, respn, 38262306a36Sopenharmony_ci SI476X_TIMEOUT_TUNE); 38362306a36Sopenharmony_ci if (!err) { 38462306a36Sopenharmony_ci wait_event_killable(core->tuning, 38562306a36Sopenharmony_ci atomic_read(&core->stc)); 38662306a36Sopenharmony_ci si476x_cmd_clear_stc(core); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return err; 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci/** 39362306a36Sopenharmony_ci * si476x_core_cmd_func_info() - send 'FUNC_INFO' command to the device 39462306a36Sopenharmony_ci * @core: device to send the command to 39562306a36Sopenharmony_ci * @info: struct si476x_func_info to fill all the information 39662306a36Sopenharmony_ci * returned by the command 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * The command requests the firmware and patch version for currently 39962306a36Sopenharmony_ci * loaded firmware (dependent on the function of the device FM/AM/WB) 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * Function returns 0 on success and negative error code on 40262306a36Sopenharmony_ci * failure 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ciint si476x_core_cmd_func_info(struct si476x_core *core, 40562306a36Sopenharmony_ci struct si476x_func_info *info) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci int err; 40862306a36Sopenharmony_ci u8 resp[CMD_FUNC_INFO_NRESP]; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_FUNC_INFO, 41162306a36Sopenharmony_ci NULL, 0, 41262306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 41362306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci info->firmware.major = resp[1]; 41662306a36Sopenharmony_ci info->firmware.minor[0] = resp[2]; 41762306a36Sopenharmony_ci info->firmware.minor[1] = resp[3]; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci info->patch_id = ((u16) resp[4] << 8) | resp[5]; 42062306a36Sopenharmony_ci info->func = resp[6]; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return err; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_func_info); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci/** 42762306a36Sopenharmony_ci * si476x_core_cmd_set_property() - send 'SET_PROPERTY' command to the device 42862306a36Sopenharmony_ci * @core: device to send the command to 42962306a36Sopenharmony_ci * @property: property address 43062306a36Sopenharmony_ci * @value: property value 43162306a36Sopenharmony_ci * 43262306a36Sopenharmony_ci * Function returns 0 on success and negative error code on 43362306a36Sopenharmony_ci * failure 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_ciint si476x_core_cmd_set_property(struct si476x_core *core, 43662306a36Sopenharmony_ci u16 property, u16 value) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci u8 resp[CMD_SET_PROPERTY_NRESP]; 43962306a36Sopenharmony_ci const u8 args[CMD_SET_PROPERTY_NARGS] = { 44062306a36Sopenharmony_ci 0x00, 44162306a36Sopenharmony_ci msb(property), 44262306a36Sopenharmony_ci lsb(property), 44362306a36Sopenharmony_ci msb(value), 44462306a36Sopenharmony_ci lsb(value), 44562306a36Sopenharmony_ci }; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_SET_PROPERTY, 44862306a36Sopenharmony_ci args, ARRAY_SIZE(args), 44962306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 45062306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_set_property); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci/** 45562306a36Sopenharmony_ci * si476x_core_cmd_get_property() - send 'GET_PROPERTY' command to the device 45662306a36Sopenharmony_ci * @core: device to send the command to 45762306a36Sopenharmony_ci * @property: property address 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci * Function return the value of property as u16 on success or a 46062306a36Sopenharmony_ci * negative error on failure 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_ciint si476x_core_cmd_get_property(struct si476x_core *core, u16 property) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci int err; 46562306a36Sopenharmony_ci u8 resp[CMD_GET_PROPERTY_NRESP]; 46662306a36Sopenharmony_ci const u8 args[CMD_GET_PROPERTY_NARGS] = { 46762306a36Sopenharmony_ci 0x00, 46862306a36Sopenharmony_ci msb(property), 46962306a36Sopenharmony_ci lsb(property), 47062306a36Sopenharmony_ci }; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_GET_PROPERTY, 47362306a36Sopenharmony_ci args, ARRAY_SIZE(args), 47462306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 47562306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 47662306a36Sopenharmony_ci if (err < 0) 47762306a36Sopenharmony_ci return err; 47862306a36Sopenharmony_ci else 47962306a36Sopenharmony_ci return get_unaligned_be16(resp + 2); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_get_property); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci/** 48462306a36Sopenharmony_ci * si476x_core_cmd_dig_audio_pin_cfg() - send 'DIG_AUDIO_PIN_CFG' command to 48562306a36Sopenharmony_ci * the device 48662306a36Sopenharmony_ci * @core: device to send the command to 48762306a36Sopenharmony_ci * @dclk: DCLK pin function configuration: 48862306a36Sopenharmony_ci * #SI476X_DCLK_NOOP - do not modify the behaviour 48962306a36Sopenharmony_ci * #SI476X_DCLK_TRISTATE - put the pin in tristate condition, 49062306a36Sopenharmony_ci * enable 1MOhm pulldown 49162306a36Sopenharmony_ci * #SI476X_DCLK_DAUDIO - set the pin to be a part of digital 49262306a36Sopenharmony_ci * audio interface 49362306a36Sopenharmony_ci * @dfs: DFS pin function configuration: 49462306a36Sopenharmony_ci * #SI476X_DFS_NOOP - do not modify the behaviour 49562306a36Sopenharmony_ci * #SI476X_DFS_TRISTATE - put the pin in tristate condition, 49662306a36Sopenharmony_ci * enable 1MOhm pulldown 49762306a36Sopenharmony_ci * SI476X_DFS_DAUDIO - set the pin to be a part of digital 49862306a36Sopenharmony_ci * audio interface 49962306a36Sopenharmony_ci * @dout: - DOUT pin function configuration: 50062306a36Sopenharmony_ci * SI476X_DOUT_NOOP - do not modify the behaviour 50162306a36Sopenharmony_ci * SI476X_DOUT_TRISTATE - put the pin in tristate condition, 50262306a36Sopenharmony_ci * enable 1MOhm pulldown 50362306a36Sopenharmony_ci * SI476X_DOUT_I2S_OUTPUT - set this pin to be digital out on I2S 50462306a36Sopenharmony_ci * port 1 50562306a36Sopenharmony_ci * SI476X_DOUT_I2S_INPUT - set this pin to be digital in on I2S 50662306a36Sopenharmony_ci * port 1 50762306a36Sopenharmony_ci * @xout: - XOUT pin function configuration: 50862306a36Sopenharmony_ci * SI476X_XOUT_NOOP - do not modify the behaviour 50962306a36Sopenharmony_ci * SI476X_XOUT_TRISTATE - put the pin in tristate condition, 51062306a36Sopenharmony_ci * enable 1MOhm pulldown 51162306a36Sopenharmony_ci * SI476X_XOUT_I2S_INPUT - set this pin to be digital in on I2S 51262306a36Sopenharmony_ci * port 1 51362306a36Sopenharmony_ci * SI476X_XOUT_MODE_SELECT - set this pin to be the input that 51462306a36Sopenharmony_ci * selects the mode of the I2S audio 51562306a36Sopenharmony_ci * combiner (analog or HD) 51662306a36Sopenharmony_ci * [SI4761/63/65/67 Only] 51762306a36Sopenharmony_ci * 51862306a36Sopenharmony_ci * Function returns 0 on success and negative error code on failure 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_ciint si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *core, 52162306a36Sopenharmony_ci enum si476x_dclk_config dclk, 52262306a36Sopenharmony_ci enum si476x_dfs_config dfs, 52362306a36Sopenharmony_ci enum si476x_dout_config dout, 52462306a36Sopenharmony_ci enum si476x_xout_config xout) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci u8 resp[CMD_DIG_AUDIO_PIN_CFG_NRESP]; 52762306a36Sopenharmony_ci const u8 args[CMD_DIG_AUDIO_PIN_CFG_NARGS] = { 52862306a36Sopenharmony_ci PIN_CFG_BYTE(dclk), 52962306a36Sopenharmony_ci PIN_CFG_BYTE(dfs), 53062306a36Sopenharmony_ci PIN_CFG_BYTE(dout), 53162306a36Sopenharmony_ci PIN_CFG_BYTE(xout), 53262306a36Sopenharmony_ci }; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_DIG_AUDIO_PIN_CFG, 53562306a36Sopenharmony_ci args, ARRAY_SIZE(args), 53662306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 53762306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci/** 54262306a36Sopenharmony_ci * si476x_core_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND' 54362306a36Sopenharmony_ci * @core: - device to send the command to 54462306a36Sopenharmony_ci * @iqclk: - IQCL pin function configuration: 54562306a36Sopenharmony_ci * SI476X_IQCLK_NOOP - do not modify the behaviour 54662306a36Sopenharmony_ci * SI476X_IQCLK_TRISTATE - put the pin in tristate condition, 54762306a36Sopenharmony_ci * enable 1MOhm pulldown 54862306a36Sopenharmony_ci * SI476X_IQCLK_IQ - set pin to be a part of I/Q interface 54962306a36Sopenharmony_ci * in master mode 55062306a36Sopenharmony_ci * @iqfs: - IQFS pin function configuration: 55162306a36Sopenharmony_ci * SI476X_IQFS_NOOP - do not modify the behaviour 55262306a36Sopenharmony_ci * SI476X_IQFS_TRISTATE - put the pin in tristate condition, 55362306a36Sopenharmony_ci * enable 1MOhm pulldown 55462306a36Sopenharmony_ci * SI476X_IQFS_IQ - set pin to be a part of I/Q interface 55562306a36Sopenharmony_ci * in master mode 55662306a36Sopenharmony_ci * @iout: - IOUT pin function configuration: 55762306a36Sopenharmony_ci * SI476X_IOUT_NOOP - do not modify the behaviour 55862306a36Sopenharmony_ci * SI476X_IOUT_TRISTATE - put the pin in tristate condition, 55962306a36Sopenharmony_ci * enable 1MOhm pulldown 56062306a36Sopenharmony_ci * SI476X_IOUT_OUTPUT - set pin to be I out 56162306a36Sopenharmony_ci * @qout: - QOUT pin function configuration: 56262306a36Sopenharmony_ci * SI476X_QOUT_NOOP - do not modify the behaviour 56362306a36Sopenharmony_ci * SI476X_QOUT_TRISTATE - put the pin in tristate condition, 56462306a36Sopenharmony_ci * enable 1MOhm pulldown 56562306a36Sopenharmony_ci * SI476X_QOUT_OUTPUT - set pin to be Q out 56662306a36Sopenharmony_ci * 56762306a36Sopenharmony_ci * Function returns 0 on success and negative error code on failure 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ciint si476x_core_cmd_zif_pin_cfg(struct si476x_core *core, 57062306a36Sopenharmony_ci enum si476x_iqclk_config iqclk, 57162306a36Sopenharmony_ci enum si476x_iqfs_config iqfs, 57262306a36Sopenharmony_ci enum si476x_iout_config iout, 57362306a36Sopenharmony_ci enum si476x_qout_config qout) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci u8 resp[CMD_ZIF_PIN_CFG_NRESP]; 57662306a36Sopenharmony_ci const u8 args[CMD_ZIF_PIN_CFG_NARGS] = { 57762306a36Sopenharmony_ci PIN_CFG_BYTE(iqclk), 57862306a36Sopenharmony_ci PIN_CFG_BYTE(iqfs), 57962306a36Sopenharmony_ci PIN_CFG_BYTE(iout), 58062306a36Sopenharmony_ci PIN_CFG_BYTE(qout), 58162306a36Sopenharmony_ci }; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_ZIF_PIN_CFG, 58462306a36Sopenharmony_ci args, ARRAY_SIZE(args), 58562306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 58662306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci/** 59162306a36Sopenharmony_ci * si476x_core_cmd_ic_link_gpo_ctl_pin_cfg - send 59262306a36Sopenharmony_ci * 'IC_LINK_GPIO_CTL_PIN_CFG' command to the device 59362306a36Sopenharmony_ci * @core: - device to send the command to 59462306a36Sopenharmony_ci * @icin: - ICIN pin function configuration: 59562306a36Sopenharmony_ci * SI476X_ICIN_NOOP - do not modify the behaviour 59662306a36Sopenharmony_ci * SI476X_ICIN_TRISTATE - put the pin in tristate condition, 59762306a36Sopenharmony_ci * enable 1MOhm pulldown 59862306a36Sopenharmony_ci * SI476X_ICIN_GPO1_HIGH - set pin to be an output, drive it high 59962306a36Sopenharmony_ci * SI476X_ICIN_GPO1_LOW - set pin to be an output, drive it low 60062306a36Sopenharmony_ci * SI476X_ICIN_IC_LINK - set the pin to be a part of Inter-Chip link 60162306a36Sopenharmony_ci * @icip: - ICIP pin function configuration: 60262306a36Sopenharmony_ci * SI476X_ICIP_NOOP - do not modify the behaviour 60362306a36Sopenharmony_ci * SI476X_ICIP_TRISTATE - put the pin in tristate condition, 60462306a36Sopenharmony_ci * enable 1MOhm pulldown 60562306a36Sopenharmony_ci * SI476X_ICIP_GPO1_HIGH - set pin to be an output, drive it high 60662306a36Sopenharmony_ci * SI476X_ICIP_GPO1_LOW - set pin to be an output, drive it low 60762306a36Sopenharmony_ci * SI476X_ICIP_IC_LINK - set the pin to be a part of Inter-Chip link 60862306a36Sopenharmony_ci * @icon: - ICON pin function configuration: 60962306a36Sopenharmony_ci * SI476X_ICON_NOOP - do not modify the behaviour 61062306a36Sopenharmony_ci * SI476X_ICON_TRISTATE - put the pin in tristate condition, 61162306a36Sopenharmony_ci * enable 1MOhm pulldown 61262306a36Sopenharmony_ci * SI476X_ICON_I2S - set the pin to be a part of audio 61362306a36Sopenharmony_ci * interface in slave mode (DCLK) 61462306a36Sopenharmony_ci * SI476X_ICON_IC_LINK - set the pin to be a part of Inter-Chip link 61562306a36Sopenharmony_ci * @icop: - ICOP pin function configuration: 61662306a36Sopenharmony_ci * SI476X_ICOP_NOOP - do not modify the behaviour 61762306a36Sopenharmony_ci * SI476X_ICOP_TRISTATE - put the pin in tristate condition, 61862306a36Sopenharmony_ci * enable 1MOhm pulldown 61962306a36Sopenharmony_ci * SI476X_ICOP_I2S - set the pin to be a part of audio 62062306a36Sopenharmony_ci * interface in slave mode (DOUT) 62162306a36Sopenharmony_ci * [Si4761/63/65/67 Only] 62262306a36Sopenharmony_ci * SI476X_ICOP_IC_LINK - set the pin to be a part of Inter-Chip link 62362306a36Sopenharmony_ci * 62462306a36Sopenharmony_ci * Function returns 0 on success and negative error code on failure 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ciint si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *core, 62762306a36Sopenharmony_ci enum si476x_icin_config icin, 62862306a36Sopenharmony_ci enum si476x_icip_config icip, 62962306a36Sopenharmony_ci enum si476x_icon_config icon, 63062306a36Sopenharmony_ci enum si476x_icop_config icop) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci u8 resp[CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP]; 63362306a36Sopenharmony_ci const u8 args[CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS] = { 63462306a36Sopenharmony_ci PIN_CFG_BYTE(icin), 63562306a36Sopenharmony_ci PIN_CFG_BYTE(icip), 63662306a36Sopenharmony_ci PIN_CFG_BYTE(icon), 63762306a36Sopenharmony_ci PIN_CFG_BYTE(icop), 63862306a36Sopenharmony_ci }; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_IC_LINK_GPO_CTL_PIN_CFG, 64162306a36Sopenharmony_ci args, ARRAY_SIZE(args), 64262306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 64362306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/** 64862306a36Sopenharmony_ci * si476x_core_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the 64962306a36Sopenharmony_ci * device 65062306a36Sopenharmony_ci * @core: - device to send the command to 65162306a36Sopenharmony_ci * @lrout: - LROUT pin function configuration: 65262306a36Sopenharmony_ci * SI476X_LROUT_NOOP - do not modify the behaviour 65362306a36Sopenharmony_ci * SI476X_LROUT_TRISTATE - put the pin in tristate condition, 65462306a36Sopenharmony_ci * enable 1MOhm pulldown 65562306a36Sopenharmony_ci * SI476X_LROUT_AUDIO - set pin to be audio output 65662306a36Sopenharmony_ci * SI476X_LROUT_MPX - set pin to be MPX output 65762306a36Sopenharmony_ci * 65862306a36Sopenharmony_ci * Function returns 0 on success and negative error code on failure 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ciint si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *core, 66162306a36Sopenharmony_ci enum si476x_lrout_config lrout) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci u8 resp[CMD_ANA_AUDIO_PIN_CFG_NRESP]; 66462306a36Sopenharmony_ci const u8 args[CMD_ANA_AUDIO_PIN_CFG_NARGS] = { 66562306a36Sopenharmony_ci PIN_CFG_BYTE(lrout), 66662306a36Sopenharmony_ci }; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_ANA_AUDIO_PIN_CFG, 66962306a36Sopenharmony_ci args, ARRAY_SIZE(args), 67062306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 67162306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci/** 67762306a36Sopenharmony_ci * si476x_core_cmd_intb_pin_cfg_a10 - send 'INTB_PIN_CFG' command to the device 67862306a36Sopenharmony_ci * @core: - device to send the command to 67962306a36Sopenharmony_ci * @intb: - INTB pin function configuration: 68062306a36Sopenharmony_ci * SI476X_INTB_NOOP - do not modify the behaviour 68162306a36Sopenharmony_ci * SI476X_INTB_TRISTATE - put the pin in tristate condition, 68262306a36Sopenharmony_ci * enable 1MOhm pulldown 68362306a36Sopenharmony_ci * SI476X_INTB_DAUDIO - set pin to be a part of digital 68462306a36Sopenharmony_ci * audio interface in slave mode 68562306a36Sopenharmony_ci * SI476X_INTB_IRQ - set pin to be an interrupt request line 68662306a36Sopenharmony_ci * @a1: - A1 pin function configuration: 68762306a36Sopenharmony_ci * SI476X_A1_NOOP - do not modify the behaviour 68862306a36Sopenharmony_ci * SI476X_A1_TRISTATE - put the pin in tristate condition, 68962306a36Sopenharmony_ci * enable 1MOhm pulldown 69062306a36Sopenharmony_ci * SI476X_A1_IRQ - set pin to be an interrupt request line 69162306a36Sopenharmony_ci * 69262306a36Sopenharmony_ci * Function returns 0 on success and negative error code on failure 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_cistatic int si476x_core_cmd_intb_pin_cfg_a10(struct si476x_core *core, 69562306a36Sopenharmony_ci enum si476x_intb_config intb, 69662306a36Sopenharmony_ci enum si476x_a1_config a1) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci u8 resp[CMD_INTB_PIN_CFG_A10_NRESP]; 69962306a36Sopenharmony_ci const u8 args[CMD_INTB_PIN_CFG_NARGS] = { 70062306a36Sopenharmony_ci PIN_CFG_BYTE(intb), 70162306a36Sopenharmony_ci PIN_CFG_BYTE(a1), 70262306a36Sopenharmony_ci }; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_INTB_PIN_CFG, 70562306a36Sopenharmony_ci args, ARRAY_SIZE(args), 70662306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 70762306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core, 71162306a36Sopenharmony_ci enum si476x_intb_config intb, 71262306a36Sopenharmony_ci enum si476x_a1_config a1) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci u8 resp[CMD_INTB_PIN_CFG_A20_NRESP]; 71562306a36Sopenharmony_ci const u8 args[CMD_INTB_PIN_CFG_NARGS] = { 71662306a36Sopenharmony_ci PIN_CFG_BYTE(intb), 71762306a36Sopenharmony_ci PIN_CFG_BYTE(a1), 71862306a36Sopenharmony_ci }; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_INTB_PIN_CFG, 72162306a36Sopenharmony_ci args, ARRAY_SIZE(args), 72262306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 72362306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci/** 72962306a36Sopenharmony_ci * si476x_core_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the 73062306a36Sopenharmony_ci * device 73162306a36Sopenharmony_ci * @core: - device to send the command to 73262306a36Sopenharmony_ci * @rsqargs: - pointer to a structure containing a group of sub-args 73362306a36Sopenharmony_ci * relevant to sending the RSQ status command 73462306a36Sopenharmony_ci * @report: - all signal quality information returned by the command 73562306a36Sopenharmony_ci * (if NULL then the output of the command is ignored) 73662306a36Sopenharmony_ci * 73762306a36Sopenharmony_ci * Function returns 0 on success and negative error code on failure 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ciint si476x_core_cmd_am_rsq_status(struct si476x_core *core, 74062306a36Sopenharmony_ci struct si476x_rsq_status_args *rsqargs, 74162306a36Sopenharmony_ci struct si476x_rsq_status_report *report) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci int err; 74462306a36Sopenharmony_ci u8 resp[CMD_AM_RSQ_STATUS_NRESP]; 74562306a36Sopenharmony_ci const u8 args[CMD_AM_RSQ_STATUS_NARGS] = { 74662306a36Sopenharmony_ci rsqargs->rsqack << 3 | rsqargs->attune << 2 | 74762306a36Sopenharmony_ci rsqargs->cancel << 1 | rsqargs->stcack, 74862306a36Sopenharmony_ci }; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_AM_RSQ_STATUS, 75162306a36Sopenharmony_ci args, ARRAY_SIZE(args), 75262306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 75362306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 75462306a36Sopenharmony_ci /* 75562306a36Sopenharmony_ci * Besides getting received signal quality information this 75662306a36Sopenharmony_ci * command can be used to just acknowledge different interrupt 75762306a36Sopenharmony_ci * flags in those cases it is useless to copy and parse 75862306a36Sopenharmony_ci * received data so user can pass NULL, and thus avoid 75962306a36Sopenharmony_ci * unnecessary copying. 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_ci if (!report) 76262306a36Sopenharmony_ci return err; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci report->snrhint = 0x08 & resp[1]; 76562306a36Sopenharmony_ci report->snrlint = 0x04 & resp[1]; 76662306a36Sopenharmony_ci report->rssihint = 0x02 & resp[1]; 76762306a36Sopenharmony_ci report->rssilint = 0x01 & resp[1]; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci report->bltf = 0x80 & resp[2]; 77062306a36Sopenharmony_ci report->snr_ready = 0x20 & resp[2]; 77162306a36Sopenharmony_ci report->rssiready = 0x08 & resp[2]; 77262306a36Sopenharmony_ci report->afcrl = 0x02 & resp[2]; 77362306a36Sopenharmony_ci report->valid = 0x01 & resp[2]; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci report->readfreq = get_unaligned_be16(resp + 3); 77662306a36Sopenharmony_ci report->freqoff = resp[5]; 77762306a36Sopenharmony_ci report->rssi = resp[6]; 77862306a36Sopenharmony_ci report->snr = resp[7]; 77962306a36Sopenharmony_ci report->lassi = resp[9]; 78062306a36Sopenharmony_ci report->hassi = resp[10]; 78162306a36Sopenharmony_ci report->mult = resp[11]; 78262306a36Sopenharmony_ci report->dev = resp[12]; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return err; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_am_rsq_status); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ciint si476x_core_cmd_fm_acf_status(struct si476x_core *core, 78962306a36Sopenharmony_ci struct si476x_acf_status_report *report) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci int err; 79262306a36Sopenharmony_ci u8 resp[CMD_FM_ACF_STATUS_NRESP]; 79362306a36Sopenharmony_ci const u8 args[CMD_FM_ACF_STATUS_NARGS] = { 79462306a36Sopenharmony_ci 0x0, 79562306a36Sopenharmony_ci }; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (!report) 79862306a36Sopenharmony_ci return -EINVAL; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_FM_ACF_STATUS, 80162306a36Sopenharmony_ci args, ARRAY_SIZE(args), 80262306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 80362306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 80462306a36Sopenharmony_ci if (err < 0) 80562306a36Sopenharmony_ci return err; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; 80862306a36Sopenharmony_ci report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; 80962306a36Sopenharmony_ci report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; 81062306a36Sopenharmony_ci report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; 81162306a36Sopenharmony_ci report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; 81262306a36Sopenharmony_ci report->smute = resp[2] & SI476X_ACF_SMUTE; 81362306a36Sopenharmony_ci report->smattn = resp[3] & SI476X_ACF_SMATTN; 81462306a36Sopenharmony_ci report->chbw = resp[4]; 81562306a36Sopenharmony_ci report->hicut = resp[5]; 81662306a36Sopenharmony_ci report->hiblend = resp[6]; 81762306a36Sopenharmony_ci report->pilot = resp[7] & SI476X_ACF_PILOT; 81862306a36Sopenharmony_ci report->stblend = resp[7] & SI476X_ACF_STBLEND; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci return err; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_fm_acf_status); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciint si476x_core_cmd_am_acf_status(struct si476x_core *core, 82562306a36Sopenharmony_ci struct si476x_acf_status_report *report) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci int err; 82862306a36Sopenharmony_ci u8 resp[CMD_AM_ACF_STATUS_NRESP]; 82962306a36Sopenharmony_ci const u8 args[CMD_AM_ACF_STATUS_NARGS] = { 83062306a36Sopenharmony_ci 0x0, 83162306a36Sopenharmony_ci }; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if (!report) 83462306a36Sopenharmony_ci return -EINVAL; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_AM_ACF_STATUS, 83762306a36Sopenharmony_ci args, ARRAY_SIZE(args), 83862306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 83962306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 84062306a36Sopenharmony_ci if (err < 0) 84162306a36Sopenharmony_ci return err; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; 84462306a36Sopenharmony_ci report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; 84562306a36Sopenharmony_ci report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; 84662306a36Sopenharmony_ci report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; 84762306a36Sopenharmony_ci report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; 84862306a36Sopenharmony_ci report->smute = resp[2] & SI476X_ACF_SMUTE; 84962306a36Sopenharmony_ci report->smattn = resp[3] & SI476X_ACF_SMATTN; 85062306a36Sopenharmony_ci report->chbw = resp[4]; 85162306a36Sopenharmony_ci report->hicut = resp[5]; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci return err; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci/** 85962306a36Sopenharmony_ci * si476x_core_cmd_fm_seek_start - send 'FM_SEEK_START' command to the 86062306a36Sopenharmony_ci * device 86162306a36Sopenharmony_ci * @core: - device to send the command to 86262306a36Sopenharmony_ci * @seekup: - if set the direction of the search is 'up' 86362306a36Sopenharmony_ci * @wrap: - if set seek wraps when hitting band limit 86462306a36Sopenharmony_ci * 86562306a36Sopenharmony_ci * This function begins search for a valid station. The station is 86662306a36Sopenharmony_ci * considered valid when 'FM_VALID_SNR_THRESHOLD' and 86762306a36Sopenharmony_ci * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria 86862306a36Sopenharmony_ci * are met. 86962306a36Sopenharmony_ci} * 87062306a36Sopenharmony_ci * Function returns 0 on success and negative error code on failure 87162306a36Sopenharmony_ci */ 87262306a36Sopenharmony_ciint si476x_core_cmd_fm_seek_start(struct si476x_core *core, 87362306a36Sopenharmony_ci bool seekup, bool wrap) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci u8 resp[CMD_FM_SEEK_START_NRESP]; 87662306a36Sopenharmony_ci const u8 args[CMD_FM_SEEK_START_NARGS] = { 87762306a36Sopenharmony_ci seekup << 3 | wrap << 2, 87862306a36Sopenharmony_ci }; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci return si476x_cmd_tune_seek_freq(core, CMD_FM_SEEK_START, 88162306a36Sopenharmony_ci args, sizeof(args), 88262306a36Sopenharmony_ci resp, sizeof(resp)); 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci/** 88762306a36Sopenharmony_ci * si476x_core_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the 88862306a36Sopenharmony_ci * device 88962306a36Sopenharmony_ci * @core: - device to send the command to 89062306a36Sopenharmony_ci * @status_only: - if set the data is not removed from RDSFIFO, 89162306a36Sopenharmony_ci * RDSFIFOUSED is not decremented and data in all the 89262306a36Sopenharmony_ci * rest RDS data contains the last valid info received 89362306a36Sopenharmony_ci * @mtfifo: if set the command clears RDS receive FIFO 89462306a36Sopenharmony_ci * @intack: if set the command clards the RDSINT bit. 89562306a36Sopenharmony_ci * @report: - all signal quality information returned by the command 89662306a36Sopenharmony_ci * (if NULL then the output of the command is ignored) 89762306a36Sopenharmony_ci * 89862306a36Sopenharmony_ci * Function returns 0 on success and negative error code on failure 89962306a36Sopenharmony_ci */ 90062306a36Sopenharmony_ciint si476x_core_cmd_fm_rds_status(struct si476x_core *core, 90162306a36Sopenharmony_ci bool status_only, 90262306a36Sopenharmony_ci bool mtfifo, 90362306a36Sopenharmony_ci bool intack, 90462306a36Sopenharmony_ci struct si476x_rds_status_report *report) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci int err; 90762306a36Sopenharmony_ci u8 resp[CMD_FM_RDS_STATUS_NRESP]; 90862306a36Sopenharmony_ci const u8 args[CMD_FM_RDS_STATUS_NARGS] = { 90962306a36Sopenharmony_ci status_only << 2 | mtfifo << 1 | intack, 91062306a36Sopenharmony_ci }; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_FM_RDS_STATUS, 91362306a36Sopenharmony_ci args, ARRAY_SIZE(args), 91462306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 91562306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 91662306a36Sopenharmony_ci /* 91762306a36Sopenharmony_ci * Besides getting RDS status information this command can be 91862306a36Sopenharmony_ci * used to just acknowledge different interrupt flags in those 91962306a36Sopenharmony_ci * cases it is useless to copy and parse received data so user 92062306a36Sopenharmony_ci * can pass NULL, and thus avoid unnecessary copying. 92162306a36Sopenharmony_ci */ 92262306a36Sopenharmony_ci if (err < 0 || report == NULL) 92362306a36Sopenharmony_ci return err; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci report->rdstpptyint = 0x10 & resp[1]; 92662306a36Sopenharmony_ci report->rdspiint = 0x08 & resp[1]; 92762306a36Sopenharmony_ci report->rdssyncint = 0x02 & resp[1]; 92862306a36Sopenharmony_ci report->rdsfifoint = 0x01 & resp[1]; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci report->tpptyvalid = 0x10 & resp[2]; 93162306a36Sopenharmony_ci report->pivalid = 0x08 & resp[2]; 93262306a36Sopenharmony_ci report->rdssync = 0x02 & resp[2]; 93362306a36Sopenharmony_ci report->rdsfifolost = 0x01 & resp[2]; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci report->tp = 0x20 & resp[3]; 93662306a36Sopenharmony_ci report->pty = 0x1f & resp[3]; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci report->pi = get_unaligned_be16(resp + 4); 93962306a36Sopenharmony_ci report->rdsfifoused = resp[6]; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci report->ble[V4L2_RDS_BLOCK_A] = 0xc0 & resp[7]; 94262306a36Sopenharmony_ci report->ble[V4L2_RDS_BLOCK_B] = 0x30 & resp[7]; 94362306a36Sopenharmony_ci report->ble[V4L2_RDS_BLOCK_C] = 0x0c & resp[7]; 94462306a36Sopenharmony_ci report->ble[V4L2_RDS_BLOCK_D] = 0x03 & resp[7]; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_A].block = V4L2_RDS_BLOCK_A; 94762306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_A].msb = resp[8]; 94862306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_A].lsb = resp[9]; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_B].block = V4L2_RDS_BLOCK_B; 95162306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_B].msb = resp[10]; 95262306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_B].lsb = resp[11]; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_C].block = V4L2_RDS_BLOCK_C; 95562306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_C].msb = resp[12]; 95662306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_C].lsb = resp[13]; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_D].block = V4L2_RDS_BLOCK_D; 95962306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_D].msb = resp[14]; 96062306a36Sopenharmony_ci report->rds[V4L2_RDS_BLOCK_D].lsb = resp[15]; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci return err; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_status); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ciint si476x_core_cmd_fm_rds_blockcount(struct si476x_core *core, 96762306a36Sopenharmony_ci bool clear, 96862306a36Sopenharmony_ci struct si476x_rds_blockcount_report *report) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci int err; 97162306a36Sopenharmony_ci u8 resp[CMD_FM_RDS_BLOCKCOUNT_NRESP]; 97262306a36Sopenharmony_ci const u8 args[CMD_FM_RDS_BLOCKCOUNT_NARGS] = { 97362306a36Sopenharmony_ci clear, 97462306a36Sopenharmony_ci }; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (!report) 97762306a36Sopenharmony_ci return -EINVAL; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_FM_RDS_BLOCKCOUNT, 98062306a36Sopenharmony_ci args, ARRAY_SIZE(args), 98162306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 98262306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (!err) { 98562306a36Sopenharmony_ci report->expected = get_unaligned_be16(resp + 2); 98662306a36Sopenharmony_ci report->received = get_unaligned_be16(resp + 4); 98762306a36Sopenharmony_ci report->uncorrectable = get_unaligned_be16(resp + 6); 98862306a36Sopenharmony_ci } 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci return err; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_blockcount); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ciint si476x_core_cmd_fm_phase_diversity(struct si476x_core *core, 99562306a36Sopenharmony_ci enum si476x_phase_diversity_mode mode) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci u8 resp[CMD_FM_PHASE_DIVERSITY_NRESP]; 99862306a36Sopenharmony_ci const u8 args[CMD_FM_PHASE_DIVERSITY_NARGS] = { 99962306a36Sopenharmony_ci mode & 0x07, 100062306a36Sopenharmony_ci }; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY, 100362306a36Sopenharmony_ci args, ARRAY_SIZE(args), 100462306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 100562306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity); 100862306a36Sopenharmony_ci/** 100962306a36Sopenharmony_ci * si476x_core_cmd_fm_phase_div_status() - get the phase diversity 101062306a36Sopenharmony_ci * status 101162306a36Sopenharmony_ci * 101262306a36Sopenharmony_ci * @core: si476x device 101362306a36Sopenharmony_ci * 101462306a36Sopenharmony_ci * NOTE caller must hold core lock 101562306a36Sopenharmony_ci * 101662306a36Sopenharmony_ci * Function returns the value of the status bit in case of success and 101762306a36Sopenharmony_ci * negative error code in case of failure. 101862306a36Sopenharmony_ci */ 101962306a36Sopenharmony_ciint si476x_core_cmd_fm_phase_div_status(struct si476x_core *core) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci int err; 102262306a36Sopenharmony_ci u8 resp[CMD_FM_PHASE_DIV_STATUS_NRESP]; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_FM_PHASE_DIV_STATUS, 102562306a36Sopenharmony_ci NULL, 0, 102662306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 102762306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci return (err < 0) ? err : resp[1]; 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci/** 103562306a36Sopenharmony_ci * si476x_core_cmd_am_seek_start - send 'FM_SEEK_START' command to the 103662306a36Sopenharmony_ci * device 103762306a36Sopenharmony_ci * @core: - device to send the command to 103862306a36Sopenharmony_ci * @seekup: - if set the direction of the search is 'up' 103962306a36Sopenharmony_ci * @wrap: - if set seek wraps when hitting band limit 104062306a36Sopenharmony_ci * 104162306a36Sopenharmony_ci * This function begins search for a valid station. The station is 104262306a36Sopenharmony_ci * considered valid when 'FM_VALID_SNR_THRESHOLD' and 104362306a36Sopenharmony_ci * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria 104462306a36Sopenharmony_ci * are met. 104562306a36Sopenharmony_ci * 104662306a36Sopenharmony_ci * Function returns 0 on success and negative error code on failure 104762306a36Sopenharmony_ci */ 104862306a36Sopenharmony_ciint si476x_core_cmd_am_seek_start(struct si476x_core *core, 104962306a36Sopenharmony_ci bool seekup, bool wrap) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci u8 resp[CMD_AM_SEEK_START_NRESP]; 105262306a36Sopenharmony_ci const u8 args[CMD_AM_SEEK_START_NARGS] = { 105362306a36Sopenharmony_ci seekup << 3 | wrap << 2, 105462306a36Sopenharmony_ci }; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci return si476x_cmd_tune_seek_freq(core, CMD_AM_SEEK_START, 105762306a36Sopenharmony_ci args, sizeof(args), 105862306a36Sopenharmony_ci resp, sizeof(resp)); 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_am_seek_start); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic int si476x_core_cmd_power_up_a10(struct si476x_core *core, 106562306a36Sopenharmony_ci struct si476x_power_up_args *puargs) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci u8 resp[CMD_POWER_UP_A10_NRESP]; 106862306a36Sopenharmony_ci const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); 106962306a36Sopenharmony_ci const bool ctsen = (core->client->irq != 0); 107062306a36Sopenharmony_ci const u8 args[CMD_POWER_UP_A10_NARGS] = { 107162306a36Sopenharmony_ci 0xF7, /* Reserved, always 0xF7 */ 107262306a36Sopenharmony_ci 0x3F & puargs->xcload, /* First two bits are reserved to be 107362306a36Sopenharmony_ci * zeros */ 107462306a36Sopenharmony_ci ctsen << 7 | intsel << 6 | 0x07, /* Last five bits 107562306a36Sopenharmony_ci * are reserved to 107662306a36Sopenharmony_ci * be written as 0x7 */ 107762306a36Sopenharmony_ci puargs->func << 4 | puargs->freq, 107862306a36Sopenharmony_ci 0x11, /* Reserved, always 0x11 */ 107962306a36Sopenharmony_ci }; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_POWER_UP, 108262306a36Sopenharmony_ci args, ARRAY_SIZE(args), 108362306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 108462306a36Sopenharmony_ci SI476X_TIMEOUT_POWER_UP); 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic int si476x_core_cmd_power_up_a20(struct si476x_core *core, 108862306a36Sopenharmony_ci struct si476x_power_up_args *puargs) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci u8 resp[CMD_POWER_UP_A20_NRESP]; 109162306a36Sopenharmony_ci const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); 109262306a36Sopenharmony_ci const bool ctsen = (core->client->irq != 0); 109362306a36Sopenharmony_ci const u8 args[CMD_POWER_UP_A20_NARGS] = { 109462306a36Sopenharmony_ci puargs->ibias6x << 7 | puargs->xstart, 109562306a36Sopenharmony_ci 0x3F & puargs->xcload, /* First two bits are reserved to be 109662306a36Sopenharmony_ci * zeros */ 109762306a36Sopenharmony_ci ctsen << 7 | intsel << 6 | puargs->fastboot << 5 | 109862306a36Sopenharmony_ci puargs->xbiashc << 3 | puargs->xbias, 109962306a36Sopenharmony_ci puargs->func << 4 | puargs->freq, 110062306a36Sopenharmony_ci 0x10 | puargs->xmode, 110162306a36Sopenharmony_ci }; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_POWER_UP, 110462306a36Sopenharmony_ci args, ARRAY_SIZE(args), 110562306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 110662306a36Sopenharmony_ci SI476X_TIMEOUT_POWER_UP); 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_cistatic int si476x_core_cmd_power_down_a10(struct si476x_core *core, 111062306a36Sopenharmony_ci struct si476x_power_down_args *pdargs) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci u8 resp[CMD_POWER_DOWN_A10_NRESP]; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_POWER_DOWN, 111562306a36Sopenharmony_ci NULL, 0, 111662306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 111762306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 111862306a36Sopenharmony_ci} 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cistatic int si476x_core_cmd_power_down_a20(struct si476x_core *core, 112162306a36Sopenharmony_ci struct si476x_power_down_args *pdargs) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci u8 resp[CMD_POWER_DOWN_A20_NRESP]; 112462306a36Sopenharmony_ci const u8 args[CMD_POWER_DOWN_A20_NARGS] = { 112562306a36Sopenharmony_ci pdargs->xosc, 112662306a36Sopenharmony_ci }; 112762306a36Sopenharmony_ci return si476x_core_send_command(core, CMD_POWER_DOWN, 112862306a36Sopenharmony_ci args, ARRAY_SIZE(args), 112962306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 113062306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic int si476x_core_cmd_am_tune_freq_a10(struct si476x_core *core, 113462306a36Sopenharmony_ci struct si476x_tune_freq_args *tuneargs) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci const int am_freq = tuneargs->freq; 113862306a36Sopenharmony_ci u8 resp[CMD_AM_TUNE_FREQ_NRESP]; 113962306a36Sopenharmony_ci const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { 114062306a36Sopenharmony_ci (tuneargs->hd << 6), 114162306a36Sopenharmony_ci msb(am_freq), 114262306a36Sopenharmony_ci lsb(am_freq), 114362306a36Sopenharmony_ci }; 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, args, 114662306a36Sopenharmony_ci sizeof(args), 114762306a36Sopenharmony_ci resp, sizeof(resp)); 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic int si476x_core_cmd_am_tune_freq_a20(struct si476x_core *core, 115162306a36Sopenharmony_ci struct si476x_tune_freq_args *tuneargs) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci const int am_freq = tuneargs->freq; 115462306a36Sopenharmony_ci u8 resp[CMD_AM_TUNE_FREQ_NRESP]; 115562306a36Sopenharmony_ci const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { 115662306a36Sopenharmony_ci (tuneargs->zifsr << 6) | (tuneargs->injside & 0x03), 115762306a36Sopenharmony_ci msb(am_freq), 115862306a36Sopenharmony_ci lsb(am_freq), 115962306a36Sopenharmony_ci }; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, 116262306a36Sopenharmony_ci args, sizeof(args), 116362306a36Sopenharmony_ci resp, sizeof(resp)); 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_cistatic int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core, 116762306a36Sopenharmony_ci struct si476x_rsq_status_args *rsqargs, 116862306a36Sopenharmony_ci struct si476x_rsq_status_report *report) 116962306a36Sopenharmony_ci{ 117062306a36Sopenharmony_ci int err; 117162306a36Sopenharmony_ci u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; 117262306a36Sopenharmony_ci const u8 args[CMD_FM_RSQ_STATUS_A10_NARGS] = { 117362306a36Sopenharmony_ci rsqargs->rsqack << 3 | rsqargs->attune << 2 | 117462306a36Sopenharmony_ci rsqargs->cancel << 1 | rsqargs->stcack, 117562306a36Sopenharmony_ci }; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, 117862306a36Sopenharmony_ci args, ARRAY_SIZE(args), 117962306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 118062306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 118162306a36Sopenharmony_ci /* 118262306a36Sopenharmony_ci * Besides getting received signal quality information this 118362306a36Sopenharmony_ci * command can be used to just acknowledge different interrupt 118462306a36Sopenharmony_ci * flags in those cases it is useless to copy and parse 118562306a36Sopenharmony_ci * received data so user can pass NULL, and thus avoid 118662306a36Sopenharmony_ci * unnecessary copying. 118762306a36Sopenharmony_ci */ 118862306a36Sopenharmony_ci if (err < 0 || report == NULL) 118962306a36Sopenharmony_ci return err; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci report->multhint = 0x80 & resp[1]; 119262306a36Sopenharmony_ci report->multlint = 0x40 & resp[1]; 119362306a36Sopenharmony_ci report->snrhint = 0x08 & resp[1]; 119462306a36Sopenharmony_ci report->snrlint = 0x04 & resp[1]; 119562306a36Sopenharmony_ci report->rssihint = 0x02 & resp[1]; 119662306a36Sopenharmony_ci report->rssilint = 0x01 & resp[1]; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci report->bltf = 0x80 & resp[2]; 119962306a36Sopenharmony_ci report->snr_ready = 0x20 & resp[2]; 120062306a36Sopenharmony_ci report->rssiready = 0x08 & resp[2]; 120162306a36Sopenharmony_ci report->afcrl = 0x02 & resp[2]; 120262306a36Sopenharmony_ci report->valid = 0x01 & resp[2]; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci report->readfreq = get_unaligned_be16(resp + 3); 120562306a36Sopenharmony_ci report->freqoff = resp[5]; 120662306a36Sopenharmony_ci report->rssi = resp[6]; 120762306a36Sopenharmony_ci report->snr = resp[7]; 120862306a36Sopenharmony_ci report->lassi = resp[9]; 120962306a36Sopenharmony_ci report->hassi = resp[10]; 121062306a36Sopenharmony_ci report->mult = resp[11]; 121162306a36Sopenharmony_ci report->dev = resp[12]; 121262306a36Sopenharmony_ci report->readantcap = get_unaligned_be16(resp + 13); 121362306a36Sopenharmony_ci report->assi = resp[15]; 121462306a36Sopenharmony_ci report->usn = resp[16]; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci return err; 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core, 122062306a36Sopenharmony_ci struct si476x_rsq_status_args *rsqargs, 122162306a36Sopenharmony_ci struct si476x_rsq_status_report *report) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci int err; 122462306a36Sopenharmony_ci u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; 122562306a36Sopenharmony_ci const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { 122662306a36Sopenharmony_ci rsqargs->primary << 4 | rsqargs->rsqack << 3 | 122762306a36Sopenharmony_ci rsqargs->attune << 2 | rsqargs->cancel << 1 | 122862306a36Sopenharmony_ci rsqargs->stcack, 122962306a36Sopenharmony_ci }; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, 123262306a36Sopenharmony_ci args, ARRAY_SIZE(args), 123362306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 123462306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 123562306a36Sopenharmony_ci /* 123662306a36Sopenharmony_ci * Besides getting received signal quality information this 123762306a36Sopenharmony_ci * command can be used to just acknowledge different interrupt 123862306a36Sopenharmony_ci * flags in those cases it is useless to copy and parse 123962306a36Sopenharmony_ci * received data so user can pass NULL, and thus avoid 124062306a36Sopenharmony_ci * unnecessary copying. 124162306a36Sopenharmony_ci */ 124262306a36Sopenharmony_ci if (err < 0 || report == NULL) 124362306a36Sopenharmony_ci return err; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci report->multhint = 0x80 & resp[1]; 124662306a36Sopenharmony_ci report->multlint = 0x40 & resp[1]; 124762306a36Sopenharmony_ci report->snrhint = 0x08 & resp[1]; 124862306a36Sopenharmony_ci report->snrlint = 0x04 & resp[1]; 124962306a36Sopenharmony_ci report->rssihint = 0x02 & resp[1]; 125062306a36Sopenharmony_ci report->rssilint = 0x01 & resp[1]; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci report->bltf = 0x80 & resp[2]; 125362306a36Sopenharmony_ci report->snr_ready = 0x20 & resp[2]; 125462306a36Sopenharmony_ci report->rssiready = 0x08 & resp[2]; 125562306a36Sopenharmony_ci report->afcrl = 0x02 & resp[2]; 125662306a36Sopenharmony_ci report->valid = 0x01 & resp[2]; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci report->readfreq = get_unaligned_be16(resp + 3); 125962306a36Sopenharmony_ci report->freqoff = resp[5]; 126062306a36Sopenharmony_ci report->rssi = resp[6]; 126162306a36Sopenharmony_ci report->snr = resp[7]; 126262306a36Sopenharmony_ci report->lassi = resp[9]; 126362306a36Sopenharmony_ci report->hassi = resp[10]; 126462306a36Sopenharmony_ci report->mult = resp[11]; 126562306a36Sopenharmony_ci report->dev = resp[12]; 126662306a36Sopenharmony_ci report->readantcap = get_unaligned_be16(resp + 13); 126762306a36Sopenharmony_ci report->assi = resp[15]; 126862306a36Sopenharmony_ci report->usn = resp[16]; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci return err; 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_cistatic int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core, 127562306a36Sopenharmony_ci struct si476x_rsq_status_args *rsqargs, 127662306a36Sopenharmony_ci struct si476x_rsq_status_report *report) 127762306a36Sopenharmony_ci{ 127862306a36Sopenharmony_ci int err; 127962306a36Sopenharmony_ci u8 resp[CMD_FM_RSQ_STATUS_A30_NRESP]; 128062306a36Sopenharmony_ci const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { 128162306a36Sopenharmony_ci rsqargs->primary << 4 | rsqargs->rsqack << 3 | 128262306a36Sopenharmony_ci rsqargs->attune << 2 | rsqargs->cancel << 1 | 128362306a36Sopenharmony_ci rsqargs->stcack, 128462306a36Sopenharmony_ci }; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, 128762306a36Sopenharmony_ci args, ARRAY_SIZE(args), 128862306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 128962306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 129062306a36Sopenharmony_ci /* 129162306a36Sopenharmony_ci * Besides getting received signal quality information this 129262306a36Sopenharmony_ci * command can be used to just acknowledge different interrupt 129362306a36Sopenharmony_ci * flags in those cases it is useless to copy and parse 129462306a36Sopenharmony_ci * received data so user can pass NULL, and thus avoid 129562306a36Sopenharmony_ci * unnecessary copying. 129662306a36Sopenharmony_ci */ 129762306a36Sopenharmony_ci if (err < 0 || report == NULL) 129862306a36Sopenharmony_ci return err; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci report->multhint = 0x80 & resp[1]; 130162306a36Sopenharmony_ci report->multlint = 0x40 & resp[1]; 130262306a36Sopenharmony_ci report->snrhint = 0x08 & resp[1]; 130362306a36Sopenharmony_ci report->snrlint = 0x04 & resp[1]; 130462306a36Sopenharmony_ci report->rssihint = 0x02 & resp[1]; 130562306a36Sopenharmony_ci report->rssilint = 0x01 & resp[1]; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci report->bltf = 0x80 & resp[2]; 130862306a36Sopenharmony_ci report->snr_ready = 0x20 & resp[2]; 130962306a36Sopenharmony_ci report->rssiready = 0x08 & resp[2]; 131062306a36Sopenharmony_ci report->injside = 0x04 & resp[2]; 131162306a36Sopenharmony_ci report->afcrl = 0x02 & resp[2]; 131262306a36Sopenharmony_ci report->valid = 0x01 & resp[2]; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci report->readfreq = get_unaligned_be16(resp + 3); 131562306a36Sopenharmony_ci report->freqoff = resp[5]; 131662306a36Sopenharmony_ci report->rssi = resp[6]; 131762306a36Sopenharmony_ci report->snr = resp[7]; 131862306a36Sopenharmony_ci report->issi = resp[8]; 131962306a36Sopenharmony_ci report->lassi = resp[9]; 132062306a36Sopenharmony_ci report->hassi = resp[10]; 132162306a36Sopenharmony_ci report->mult = resp[11]; 132262306a36Sopenharmony_ci report->dev = resp[12]; 132362306a36Sopenharmony_ci report->readantcap = get_unaligned_be16(resp + 13); 132462306a36Sopenharmony_ci report->assi = resp[15]; 132562306a36Sopenharmony_ci report->usn = resp[16]; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci report->pilotdev = resp[17]; 132862306a36Sopenharmony_ci report->rdsdev = resp[18]; 132962306a36Sopenharmony_ci report->assidev = resp[19]; 133062306a36Sopenharmony_ci report->strongdev = resp[20]; 133162306a36Sopenharmony_ci report->rdspi = get_unaligned_be16(resp + 21); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci return err; 133462306a36Sopenharmony_ci} 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_cistatic int si476x_core_cmd_fm_tune_freq_a10(struct si476x_core *core, 133762306a36Sopenharmony_ci struct si476x_tune_freq_args *tuneargs) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci u8 resp[CMD_FM_TUNE_FREQ_NRESP]; 134062306a36Sopenharmony_ci const u8 args[CMD_FM_TUNE_FREQ_A10_NARGS] = { 134162306a36Sopenharmony_ci (tuneargs->hd << 6) | (tuneargs->tunemode << 4) 134262306a36Sopenharmony_ci | (tuneargs->smoothmetrics << 2), 134362306a36Sopenharmony_ci msb(tuneargs->freq), 134462306a36Sopenharmony_ci lsb(tuneargs->freq), 134562306a36Sopenharmony_ci msb(tuneargs->antcap), 134662306a36Sopenharmony_ci lsb(tuneargs->antcap) 134762306a36Sopenharmony_ci }; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, 135062306a36Sopenharmony_ci args, sizeof(args), 135162306a36Sopenharmony_ci resp, sizeof(resp)); 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic int si476x_core_cmd_fm_tune_freq_a20(struct si476x_core *core, 135562306a36Sopenharmony_ci struct si476x_tune_freq_args *tuneargs) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci u8 resp[CMD_FM_TUNE_FREQ_NRESP]; 135862306a36Sopenharmony_ci const u8 args[CMD_FM_TUNE_FREQ_A20_NARGS] = { 135962306a36Sopenharmony_ci (tuneargs->hd << 6) | (tuneargs->tunemode << 4) 136062306a36Sopenharmony_ci | (tuneargs->smoothmetrics << 2) | (tuneargs->injside), 136162306a36Sopenharmony_ci msb(tuneargs->freq), 136262306a36Sopenharmony_ci lsb(tuneargs->freq), 136362306a36Sopenharmony_ci }; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, 136662306a36Sopenharmony_ci args, sizeof(args), 136762306a36Sopenharmony_ci resp, sizeof(resp)); 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_cistatic int si476x_core_cmd_agc_status_a20(struct si476x_core *core, 137162306a36Sopenharmony_ci struct si476x_agc_status_report *report) 137262306a36Sopenharmony_ci{ 137362306a36Sopenharmony_ci int err; 137462306a36Sopenharmony_ci u8 resp[CMD_AGC_STATUS_NRESP_A20]; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (!report) 137762306a36Sopenharmony_ci return -EINVAL; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_AGC_STATUS, 138062306a36Sopenharmony_ci NULL, 0, 138162306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 138262306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 138362306a36Sopenharmony_ci if (err < 0) 138462306a36Sopenharmony_ci return err; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci report->mxhi = resp[1] & SI476X_AGC_MXHI; 138762306a36Sopenharmony_ci report->mxlo = resp[1] & SI476X_AGC_MXLO; 138862306a36Sopenharmony_ci report->lnahi = resp[1] & SI476X_AGC_LNAHI; 138962306a36Sopenharmony_ci report->lnalo = resp[1] & SI476X_AGC_LNALO; 139062306a36Sopenharmony_ci report->fmagc1 = resp[2]; 139162306a36Sopenharmony_ci report->fmagc2 = resp[3]; 139262306a36Sopenharmony_ci report->pgagain = resp[4]; 139362306a36Sopenharmony_ci report->fmwblang = resp[5]; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci return err; 139662306a36Sopenharmony_ci} 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_cistatic int si476x_core_cmd_agc_status_a10(struct si476x_core *core, 139962306a36Sopenharmony_ci struct si476x_agc_status_report *report) 140062306a36Sopenharmony_ci{ 140162306a36Sopenharmony_ci int err; 140262306a36Sopenharmony_ci u8 resp[CMD_AGC_STATUS_NRESP_A10]; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if (!report) 140562306a36Sopenharmony_ci return -EINVAL; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci err = si476x_core_send_command(core, CMD_AGC_STATUS, 140862306a36Sopenharmony_ci NULL, 0, 140962306a36Sopenharmony_ci resp, ARRAY_SIZE(resp), 141062306a36Sopenharmony_ci SI476X_DEFAULT_TIMEOUT); 141162306a36Sopenharmony_ci if (err < 0) 141262306a36Sopenharmony_ci return err; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci report->mxhi = resp[1] & SI476X_AGC_MXHI; 141562306a36Sopenharmony_ci report->mxlo = resp[1] & SI476X_AGC_MXLO; 141662306a36Sopenharmony_ci report->lnahi = resp[1] & SI476X_AGC_LNAHI; 141762306a36Sopenharmony_ci report->lnalo = resp[1] & SI476X_AGC_LNALO; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci return err; 142062306a36Sopenharmony_ci} 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_citypedef int (*tune_freq_func_t) (struct si476x_core *core, 142362306a36Sopenharmony_ci struct si476x_tune_freq_args *tuneargs); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_cistatic struct { 142662306a36Sopenharmony_ci int (*power_up)(struct si476x_core *, 142762306a36Sopenharmony_ci struct si476x_power_up_args *); 142862306a36Sopenharmony_ci int (*power_down)(struct si476x_core *, 142962306a36Sopenharmony_ci struct si476x_power_down_args *); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci tune_freq_func_t fm_tune_freq; 143262306a36Sopenharmony_ci tune_freq_func_t am_tune_freq; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci int (*fm_rsq_status)(struct si476x_core *, 143562306a36Sopenharmony_ci struct si476x_rsq_status_args *, 143662306a36Sopenharmony_ci struct si476x_rsq_status_report *); 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci int (*agc_status)(struct si476x_core *, 143962306a36Sopenharmony_ci struct si476x_agc_status_report *); 144062306a36Sopenharmony_ci int (*intb_pin_cfg)(struct si476x_core *core, 144162306a36Sopenharmony_ci enum si476x_intb_config intb, 144262306a36Sopenharmony_ci enum si476x_a1_config a1); 144362306a36Sopenharmony_ci} si476x_cmds_vtable[] = { 144462306a36Sopenharmony_ci [SI476X_REVISION_A10] = { 144562306a36Sopenharmony_ci .power_up = si476x_core_cmd_power_up_a10, 144662306a36Sopenharmony_ci .power_down = si476x_core_cmd_power_down_a10, 144762306a36Sopenharmony_ci .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a10, 144862306a36Sopenharmony_ci .am_tune_freq = si476x_core_cmd_am_tune_freq_a10, 144962306a36Sopenharmony_ci .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a10, 145062306a36Sopenharmony_ci .agc_status = si476x_core_cmd_agc_status_a10, 145162306a36Sopenharmony_ci .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a10, 145262306a36Sopenharmony_ci }, 145362306a36Sopenharmony_ci [SI476X_REVISION_A20] = { 145462306a36Sopenharmony_ci .power_up = si476x_core_cmd_power_up_a20, 145562306a36Sopenharmony_ci .power_down = si476x_core_cmd_power_down_a20, 145662306a36Sopenharmony_ci .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, 145762306a36Sopenharmony_ci .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, 145862306a36Sopenharmony_ci .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a20, 145962306a36Sopenharmony_ci .agc_status = si476x_core_cmd_agc_status_a20, 146062306a36Sopenharmony_ci .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, 146162306a36Sopenharmony_ci }, 146262306a36Sopenharmony_ci [SI476X_REVISION_A30] = { 146362306a36Sopenharmony_ci .power_up = si476x_core_cmd_power_up_a20, 146462306a36Sopenharmony_ci .power_down = si476x_core_cmd_power_down_a20, 146562306a36Sopenharmony_ci .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, 146662306a36Sopenharmony_ci .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, 146762306a36Sopenharmony_ci .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a30, 146862306a36Sopenharmony_ci .agc_status = si476x_core_cmd_agc_status_a20, 146962306a36Sopenharmony_ci .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, 147062306a36Sopenharmony_ci }, 147162306a36Sopenharmony_ci}; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ciint si476x_core_cmd_power_up(struct si476x_core *core, 147462306a36Sopenharmony_ci struct si476x_power_up_args *args) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci BUG_ON(core->revision > SI476X_REVISION_A30 || 147762306a36Sopenharmony_ci core->revision == -1); 147862306a36Sopenharmony_ci return si476x_cmds_vtable[core->revision].power_up(core, args); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_power_up); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ciint si476x_core_cmd_power_down(struct si476x_core *core, 148362306a36Sopenharmony_ci struct si476x_power_down_args *args) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci BUG_ON(core->revision > SI476X_REVISION_A30 || 148662306a36Sopenharmony_ci core->revision == -1); 148762306a36Sopenharmony_ci return si476x_cmds_vtable[core->revision].power_down(core, args); 148862306a36Sopenharmony_ci} 148962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_power_down); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ciint si476x_core_cmd_fm_tune_freq(struct si476x_core *core, 149262306a36Sopenharmony_ci struct si476x_tune_freq_args *args) 149362306a36Sopenharmony_ci{ 149462306a36Sopenharmony_ci BUG_ON(core->revision > SI476X_REVISION_A30 || 149562306a36Sopenharmony_ci core->revision == -1); 149662306a36Sopenharmony_ci return si476x_cmds_vtable[core->revision].fm_tune_freq(core, args); 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_fm_tune_freq); 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ciint si476x_core_cmd_am_tune_freq(struct si476x_core *core, 150162306a36Sopenharmony_ci struct si476x_tune_freq_args *args) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci BUG_ON(core->revision > SI476X_REVISION_A30 || 150462306a36Sopenharmony_ci core->revision == -1); 150562306a36Sopenharmony_ci return si476x_cmds_vtable[core->revision].am_tune_freq(core, args); 150662306a36Sopenharmony_ci} 150762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_am_tune_freq); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ciint si476x_core_cmd_fm_rsq_status(struct si476x_core *core, 151062306a36Sopenharmony_ci struct si476x_rsq_status_args *args, 151162306a36Sopenharmony_ci struct si476x_rsq_status_report *report) 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci{ 151462306a36Sopenharmony_ci BUG_ON(core->revision > SI476X_REVISION_A30 || 151562306a36Sopenharmony_ci core->revision == -1); 151662306a36Sopenharmony_ci return si476x_cmds_vtable[core->revision].fm_rsq_status(core, args, 151762306a36Sopenharmony_ci report); 151862306a36Sopenharmony_ci} 151962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rsq_status); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ciint si476x_core_cmd_agc_status(struct si476x_core *core, 152262306a36Sopenharmony_ci struct si476x_agc_status_report *report) 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci{ 152562306a36Sopenharmony_ci BUG_ON(core->revision > SI476X_REVISION_A30 || 152662306a36Sopenharmony_ci core->revision == -1); 152762306a36Sopenharmony_ci return si476x_cmds_vtable[core->revision].agc_status(core, report); 152862306a36Sopenharmony_ci} 152962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_agc_status); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ciint si476x_core_cmd_intb_pin_cfg(struct si476x_core *core, 153262306a36Sopenharmony_ci enum si476x_intb_config intb, 153362306a36Sopenharmony_ci enum si476x_a1_config a1) 153462306a36Sopenharmony_ci{ 153562306a36Sopenharmony_ci BUG_ON(core->revision > SI476X_REVISION_A30 || 153662306a36Sopenharmony_ci core->revision == -1); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci return si476x_cmds_vtable[core->revision].intb_pin_cfg(core, intb, a1); 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(si476x_core_cmd_intb_pin_cfg); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 154362306a36Sopenharmony_ciMODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); 154462306a36Sopenharmony_ciMODULE_DESCRIPTION("API for command exchange for si476x"); 1545