int cx25840_loadfw(struct i2c_client *client) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); const struct firmware *fw = NULL; u8 buffer[FWSEND]; const u8 *ptr; const char *fwname = get_fw_name(client); int size, retval; int max_buf_size = FWSEND; u32 gpio_oe = 0, gpio_da = 0; if (is_cx2388x(state)) { /* Preserve the GPIO OE and output bits */ gpio_oe = cx25840_read(client, 0x160); gpio_da = cx25840_read(client, 0x164); } /* cx231xx cannot accept more than 16 bytes at a time */ if (is_cx231xx(state) && max_buf_size > 16) max_buf_size = 16; if (request_firmware(&fw, fwname, FWDEV(client)) != 0) return -EINVAL; start_fw_load(client); buffer[0] = 0x08; buffer[1] = 0x02; size = fw->size; ptr = fw->data; while (size > 0) { int len = min(max_buf_size - 2, size); memcpy(buffer + 2, ptr, len); retval = fw_write(client, buffer, len + 2); if (retval < 0) { release_firmware(fw); return retval; } size -= len; ptr += len; } end_fw_load(client); size = fw->size; release_firmware(fw); if (is_cx2388x(state)) { /* Restore GPIO configuration after f/w load */ cx25840_write(client, 0x160, gpio_oe); cx25840_write(client, 0x164, gpio_da); } return check_fw_load(client, size); }
static const char *get_fw_name(struct i2c_client *client) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); if (firmware[0]) return firmware; if (is_cx2388x(state)) return CX2388x_FIRMWARE; if (is_cx231xx(state)) return CX231xx_FIRMWARE; return CX25840_FIRMWARE; }
static const char *get_fw_name(struct i2c_client *client) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); if (firmware[0]) return firmware; if (is_cx2388x(state)) return "v4l-cx23885-avcore-01.fw"; if (is_cx231xx(state)) return "v4l-cx231xx-avcore-01.fw"; return "v4l-cx25840.fw"; }
static int set_audclk_freq(struct i2c_client *client, u32 freq) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); if (freq != 32000 && freq != 44100 && freq != 48000) return -EINVAL; if (is_cx231xx(state)) return cx231xx_set_audclk_freq(client, freq); if (is_cx2388x(state)) return cx23885_set_audclk_freq(client, freq); if (is_cx2583x(state)) return cx25836_set_audclk_freq(client, freq); return cx25840_set_audclk_freq(client, freq); }
void cx25840_audio_set_path(struct i2c_client *client) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); if (!is_cx2583x(state)) { /* assert soft reset */ cx25840_and_or(client, 0x810, ~0x1, 0x01); /* stop microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0); /* Mute everything to prevent the PFFT! */ cx25840_write(client, 0x8d3, 0x1f); if (state->aud_input == CX25840_AUDIO_SERIAL) { /* Set Path1 to Serial Audio Input */ cx25840_write4(client, 0x8d0, 0x01011012); /* The microcontroller should not be started for the * non-tuner inputs: autodetection is specific for * TV audio. */ } else { /* Set Path1 to Analog Demod Main Channel */ cx25840_write4(client, 0x8d0, 0x1f063870); } } set_audclk_freq(client, state->audclk_freq); if (!is_cx2583x(state)) { if (state->aud_input != CX25840_AUDIO_SERIAL) { /* When the microcontroller detects the * audio format, it will unmute the lines */ cx25840_and_or(client, 0x803, ~0x10, 0x10); } /* deassert soft reset */ cx25840_and_or(client, 0x810, ~0x1, 0x00); /* Ensure the controller is running when we exit */ if (is_cx2388x(state) || is_cx231xx(state)) cx25840_and_or(client, 0x803, ~0x10, 0x10); } }