162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* cx25840 audio functions
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/videodev2.h>
762306a36Sopenharmony_ci#include <linux/i2c.h>
862306a36Sopenharmony_ci#include <media/v4l2-common.h>
962306a36Sopenharmony_ci#include <media/drv-intf/cx25840.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "cx25840-core.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/*
1462306a36Sopenharmony_ci * Note: The PLL and SRC parameters are based on a reference frequency that
1562306a36Sopenharmony_ci * would ideally be:
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * However, it's not the exact reference frequency that matters, only that the
2062306a36Sopenharmony_ci * firmware and modules that comprise the driver for a particular board all
2162306a36Sopenharmony_ci * use the same value (close to the ideal value).
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Comments below will note which reference frequency is assumed for various
2462306a36Sopenharmony_ci * parameters.  They will usually be one of
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci *	ref_freq = 28.636360 MHz
2762306a36Sopenharmony_ci *		or
2862306a36Sopenharmony_ci *	ref_freq = 28.636363 MHz
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	if (state->aud_input != CX25840_AUDIO_SERIAL) {
3662306a36Sopenharmony_ci		switch (freq) {
3762306a36Sopenharmony_ci		case 32000:
3862306a36Sopenharmony_ci			/*
3962306a36Sopenharmony_ci			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
4062306a36Sopenharmony_ci			 * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10
4162306a36Sopenharmony_ci			 */
4262306a36Sopenharmony_ci			cx25840_write4(client, 0x108, 0x1006040f);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci			/*
4562306a36Sopenharmony_ci			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
4662306a36Sopenharmony_ci			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
4762306a36Sopenharmony_ci			 * 432 MHz pre-postdivide
4862306a36Sopenharmony_ci			 */
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci			/*
5162306a36Sopenharmony_ci			 * AUX_PLL Fraction = 0x1bb39ee
5262306a36Sopenharmony_ci			 * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384
5362306a36Sopenharmony_ci			 * 196.6 MHz pre-postdivide
5462306a36Sopenharmony_ci			 * FIXME < 200 MHz is out of specified valid range
5562306a36Sopenharmony_ci			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
5662306a36Sopenharmony_ci			 */
5762306a36Sopenharmony_ci			cx25840_write4(client, 0x110, 0x01bb39ee);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci			/*
6062306a36Sopenharmony_ci			 * SA_MCLK_SEL = 1
6162306a36Sopenharmony_ci			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
6262306a36Sopenharmony_ci			 */
6362306a36Sopenharmony_ci			cx25840_write(client, 0x127, 0x50);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci			if (is_cx2583x(state))
6662306a36Sopenharmony_ci				break;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci			/* src3/4/6_ctl */
6962306a36Sopenharmony_ci			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
7062306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x0801f77f);
7162306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x0801f77f);
7262306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x0801f77f);
7362306a36Sopenharmony_ci			break;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		case 44100:
7662306a36Sopenharmony_ci			/*
7762306a36Sopenharmony_ci			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
7862306a36Sopenharmony_ci			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10
7962306a36Sopenharmony_ci			 */
8062306a36Sopenharmony_ci			cx25840_write4(client, 0x108, 0x1009040f);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci			/*
8362306a36Sopenharmony_ci			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
8462306a36Sopenharmony_ci			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
8562306a36Sopenharmony_ci			 * 432 MHz pre-postdivide
8662306a36Sopenharmony_ci			 */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci			/*
8962306a36Sopenharmony_ci			 * AUX_PLL Fraction = 0x0ec6bd6
9062306a36Sopenharmony_ci			 * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384
9162306a36Sopenharmony_ci			 * 271 MHz pre-postdivide
9262306a36Sopenharmony_ci			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
9362306a36Sopenharmony_ci			 */
9462306a36Sopenharmony_ci			cx25840_write4(client, 0x110, 0x00ec6bd6);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci			/*
9762306a36Sopenharmony_ci			 * SA_MCLK_SEL = 1
9862306a36Sopenharmony_ci			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
9962306a36Sopenharmony_ci			 */
10062306a36Sopenharmony_ci			cx25840_write(client, 0x127, 0x50);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci			if (is_cx2583x(state))
10362306a36Sopenharmony_ci				break;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci			/* src3/4/6_ctl */
10662306a36Sopenharmony_ci			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
10762306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08016d59);
10862306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08016d59);
10962306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08016d59);
11062306a36Sopenharmony_ci			break;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		case 48000:
11362306a36Sopenharmony_ci			/*
11462306a36Sopenharmony_ci			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
11562306a36Sopenharmony_ci			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10
11662306a36Sopenharmony_ci			 */
11762306a36Sopenharmony_ci			cx25840_write4(client, 0x108, 0x100a040f);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci			/*
12062306a36Sopenharmony_ci			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
12162306a36Sopenharmony_ci			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
12262306a36Sopenharmony_ci			 * 432 MHz pre-postdivide
12362306a36Sopenharmony_ci			 */
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci			/*
12662306a36Sopenharmony_ci			 * AUX_PLL Fraction = 0x098d6e5
12762306a36Sopenharmony_ci			 * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384
12862306a36Sopenharmony_ci			 * 295 MHz pre-postdivide
12962306a36Sopenharmony_ci			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
13062306a36Sopenharmony_ci			 */
13162306a36Sopenharmony_ci			cx25840_write4(client, 0x110, 0x0098d6e5);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci			/*
13462306a36Sopenharmony_ci			 * SA_MCLK_SEL = 1
13562306a36Sopenharmony_ci			 * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider
13662306a36Sopenharmony_ci			 */
13762306a36Sopenharmony_ci			cx25840_write(client, 0x127, 0x50);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci			if (is_cx2583x(state))
14062306a36Sopenharmony_ci				break;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci			/* src3/4/6_ctl */
14362306a36Sopenharmony_ci			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
14462306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08014faa);
14562306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08014faa);
14662306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08014faa);
14762306a36Sopenharmony_ci			break;
14862306a36Sopenharmony_ci		}
14962306a36Sopenharmony_ci	} else {
15062306a36Sopenharmony_ci		switch (freq) {
15162306a36Sopenharmony_ci		case 32000:
15262306a36Sopenharmony_ci			/*
15362306a36Sopenharmony_ci			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
15462306a36Sopenharmony_ci			 * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e
15562306a36Sopenharmony_ci			 */
15662306a36Sopenharmony_ci			cx25840_write4(client, 0x108, 0x1e08040f);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci			/*
15962306a36Sopenharmony_ci			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
16062306a36Sopenharmony_ci			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
16162306a36Sopenharmony_ci			 * 432 MHz pre-postdivide
16262306a36Sopenharmony_ci			 */
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci			/*
16562306a36Sopenharmony_ci			 * AUX_PLL Fraction = 0x12a0869
16662306a36Sopenharmony_ci			 * 28636363 * 0x8.9504348/0x1e = 32000 * 256
16762306a36Sopenharmony_ci			 * 246 MHz pre-postdivide
16862306a36Sopenharmony_ci			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
16962306a36Sopenharmony_ci			 */
17062306a36Sopenharmony_ci			cx25840_write4(client, 0x110, 0x012a0869);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci			/*
17362306a36Sopenharmony_ci			 * SA_MCLK_SEL = 1
17462306a36Sopenharmony_ci			 * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider
17562306a36Sopenharmony_ci			 */
17662306a36Sopenharmony_ci			cx25840_write(client, 0x127, 0x54);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci			if (is_cx2583x(state))
17962306a36Sopenharmony_ci				break;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci			/* src1_ctl */
18262306a36Sopenharmony_ci			/* 0x1.0000 = 32000/32000 */
18362306a36Sopenharmony_ci			cx25840_write4(client, 0x8f8, 0x08010000);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci			/* src3/4/6_ctl */
18662306a36Sopenharmony_ci			/* 0x2.0000 = 2 * (32000/32000) */
18762306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08020000);
18862306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08020000);
18962306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08020000);
19062306a36Sopenharmony_ci			break;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		case 44100:
19362306a36Sopenharmony_ci			/*
19462306a36Sopenharmony_ci			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
19562306a36Sopenharmony_ci			 * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18
19662306a36Sopenharmony_ci			 */
19762306a36Sopenharmony_ci			cx25840_write4(client, 0x108, 0x1809040f);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci			/*
20062306a36Sopenharmony_ci			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
20162306a36Sopenharmony_ci			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
20262306a36Sopenharmony_ci			 * 432 MHz pre-postdivide
20362306a36Sopenharmony_ci			 */
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci			/*
20662306a36Sopenharmony_ci			 * AUX_PLL Fraction = 0x0ec6bd6
20762306a36Sopenharmony_ci			 * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256
20862306a36Sopenharmony_ci			 * 271 MHz pre-postdivide
20962306a36Sopenharmony_ci			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
21062306a36Sopenharmony_ci			 */
21162306a36Sopenharmony_ci			cx25840_write4(client, 0x110, 0x00ec6bd6);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci			/*
21462306a36Sopenharmony_ci			 * SA_MCLK_SEL = 1
21562306a36Sopenharmony_ci			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
21662306a36Sopenharmony_ci			 */
21762306a36Sopenharmony_ci			cx25840_write(client, 0x127, 0x50);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci			if (is_cx2583x(state))
22062306a36Sopenharmony_ci				break;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci			/* src1_ctl */
22362306a36Sopenharmony_ci			/* 0x1.60cd = 44100/32000 */
22462306a36Sopenharmony_ci			cx25840_write4(client, 0x8f8, 0x080160cd);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci			/* src3/4/6_ctl */
22762306a36Sopenharmony_ci			/* 0x1.7385 = 2 * (32000/44100) */
22862306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08017385);
22962306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08017385);
23062306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08017385);
23162306a36Sopenharmony_ci			break;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		case 48000:
23462306a36Sopenharmony_ci			/*
23562306a36Sopenharmony_ci			 * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04
23662306a36Sopenharmony_ci			 * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18
23762306a36Sopenharmony_ci			 */
23862306a36Sopenharmony_ci			cx25840_write4(client, 0x108, 0x180a040f);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci			/*
24162306a36Sopenharmony_ci			 * VID_PLL Fraction (register 0x10c) = 0x2be2fe
24262306a36Sopenharmony_ci			 * 28636360 * 0xf.15f17f0/4 = 108 MHz
24362306a36Sopenharmony_ci			 * 432 MHz pre-postdivide
24462306a36Sopenharmony_ci			 */
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci			/*
24762306a36Sopenharmony_ci			 * AUX_PLL Fraction = 0x098d6e5
24862306a36Sopenharmony_ci			 * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256
24962306a36Sopenharmony_ci			 * 295 MHz pre-postdivide
25062306a36Sopenharmony_ci			 * FIXME 28636363 ref_freq doesn't match VID PLL ref
25162306a36Sopenharmony_ci			 */
25262306a36Sopenharmony_ci			cx25840_write4(client, 0x110, 0x0098d6e5);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci			/*
25562306a36Sopenharmony_ci			 * SA_MCLK_SEL = 1
25662306a36Sopenharmony_ci			 * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider
25762306a36Sopenharmony_ci			 */
25862306a36Sopenharmony_ci			cx25840_write(client, 0x127, 0x50);
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci			if (is_cx2583x(state))
26162306a36Sopenharmony_ci				break;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci			/* src1_ctl */
26462306a36Sopenharmony_ci			/* 0x1.8000 = 48000/32000 */
26562306a36Sopenharmony_ci			cx25840_write4(client, 0x8f8, 0x08018000);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci			/* src3/4/6_ctl */
26862306a36Sopenharmony_ci			/* 0x1.5555 = 2 * (32000/48000) */
26962306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08015555);
27062306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08015555);
27162306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08015555);
27262306a36Sopenharmony_ci			break;
27362306a36Sopenharmony_ci		}
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	state->audclk_freq = freq;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	return cx25840_set_audclk_freq(client, freq);
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (state->aud_input != CX25840_AUDIO_SERIAL) {
29162306a36Sopenharmony_ci		switch (freq) {
29262306a36Sopenharmony_ci		case 32000:
29362306a36Sopenharmony_ci		case 44100:
29462306a36Sopenharmony_ci		case 48000:
29562306a36Sopenharmony_ci			/* We don't have register values
29662306a36Sopenharmony_ci			 * so avoid destroying registers. */
29762306a36Sopenharmony_ci			/* FIXME return -EINVAL; */
29862306a36Sopenharmony_ci			break;
29962306a36Sopenharmony_ci		}
30062306a36Sopenharmony_ci	} else {
30162306a36Sopenharmony_ci		switch (freq) {
30262306a36Sopenharmony_ci		case 32000:
30362306a36Sopenharmony_ci		case 44100:
30462306a36Sopenharmony_ci			/* We don't have register values
30562306a36Sopenharmony_ci			 * so avoid destroying registers. */
30662306a36Sopenharmony_ci			/* FIXME return -EINVAL; */
30762306a36Sopenharmony_ci			break;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		case 48000:
31062306a36Sopenharmony_ci			/* src1_ctl */
31162306a36Sopenharmony_ci			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
31262306a36Sopenharmony_ci			cx25840_write4(client, 0x8f8, 0x0801867c);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci			/* src3/4/6_ctl */
31562306a36Sopenharmony_ci			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
31662306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08014faa);
31762306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08014faa);
31862306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08014faa);
31962306a36Sopenharmony_ci			break;
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	state->audclk_freq = freq;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	return 0;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	if (state->aud_input != CX25840_AUDIO_SERIAL) {
33362306a36Sopenharmony_ci		switch (freq) {
33462306a36Sopenharmony_ci		case 32000:
33562306a36Sopenharmony_ci			/* src3/4/6_ctl */
33662306a36Sopenharmony_ci			/* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */
33762306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x0801f77f);
33862306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x0801f77f);
33962306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x0801f77f);
34062306a36Sopenharmony_ci			break;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci		case 44100:
34362306a36Sopenharmony_ci			/* src3/4/6_ctl */
34462306a36Sopenharmony_ci			/* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */
34562306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08016d59);
34662306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08016d59);
34762306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08016d59);
34862306a36Sopenharmony_ci			break;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		case 48000:
35162306a36Sopenharmony_ci			/* src3/4/6_ctl */
35262306a36Sopenharmony_ci			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
35362306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08014faa);
35462306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08014faa);
35562306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08014faa);
35662306a36Sopenharmony_ci			break;
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci	} else {
35962306a36Sopenharmony_ci		switch (freq) {
36062306a36Sopenharmony_ci		/* FIXME These cases make different assumptions about audclk */
36162306a36Sopenharmony_ci		case 32000:
36262306a36Sopenharmony_ci			/* src1_ctl */
36362306a36Sopenharmony_ci			/* 0x1.0000 = 32000/32000 */
36462306a36Sopenharmony_ci			cx25840_write4(client, 0x8f8, 0x08010000);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci			/* src3/4/6_ctl */
36762306a36Sopenharmony_ci			/* 0x2.0000 = 2 * (32000/32000) */
36862306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08020000);
36962306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08020000);
37062306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08020000);
37162306a36Sopenharmony_ci			break;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		case 44100:
37462306a36Sopenharmony_ci			/* src1_ctl */
37562306a36Sopenharmony_ci			/* 0x1.60cd = 44100/32000 */
37662306a36Sopenharmony_ci			cx25840_write4(client, 0x8f8, 0x080160cd);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci			/* src3/4/6_ctl */
37962306a36Sopenharmony_ci			/* 0x1.7385 = 2 * (32000/44100) */
38062306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08017385);
38162306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08017385);
38262306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08017385);
38362306a36Sopenharmony_ci			break;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci		case 48000:
38662306a36Sopenharmony_ci			/* src1_ctl */
38762306a36Sopenharmony_ci			/* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */
38862306a36Sopenharmony_ci			cx25840_write4(client, 0x8f8, 0x0801867c);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci			/* src3/4/6_ctl */
39162306a36Sopenharmony_ci			/* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */
39262306a36Sopenharmony_ci			cx25840_write4(client, 0x900, 0x08014faa);
39362306a36Sopenharmony_ci			cx25840_write4(client, 0x904, 0x08014faa);
39462306a36Sopenharmony_ci			cx25840_write4(client, 0x90c, 0x08014faa);
39562306a36Sopenharmony_ci			break;
39662306a36Sopenharmony_ci		}
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	state->audclk_freq = freq;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	return 0;
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic int set_audclk_freq(struct i2c_client *client, u32 freq)
40562306a36Sopenharmony_ci{
40662306a36Sopenharmony_ci	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (freq != 32000 && freq != 44100 && freq != 48000)
40962306a36Sopenharmony_ci		return -EINVAL;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (is_cx231xx(state))
41262306a36Sopenharmony_ci		return cx231xx_set_audclk_freq(client, freq);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	if (is_cx2388x(state))
41562306a36Sopenharmony_ci		return cx23885_set_audclk_freq(client, freq);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (is_cx2583x(state))
41862306a36Sopenharmony_ci		return cx25836_set_audclk_freq(client, freq);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	return cx25840_set_audclk_freq(client, freq);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_civoid cx25840_audio_set_path(struct i2c_client *client)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct cx25840_state *state = to_state(i2c_get_clientdata(client));
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (!is_cx2583x(state)) {
42862306a36Sopenharmony_ci		/* assert soft reset */
42962306a36Sopenharmony_ci		cx25840_and_or(client, 0x810, ~0x1, 0x01);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		/* stop microcontroller */
43262306a36Sopenharmony_ci		cx25840_and_or(client, 0x803, ~0x10, 0);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		/* Mute everything to prevent the PFFT! */
43562306a36Sopenharmony_ci		cx25840_write(client, 0x8d3, 0x1f);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		if (state->aud_input == CX25840_AUDIO_SERIAL) {
43862306a36Sopenharmony_ci			/* Set Path1 to Serial Audio Input */
43962306a36Sopenharmony_ci			cx25840_write4(client, 0x8d0, 0x01011012);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci			/* The microcontroller should not be started for the
44262306a36Sopenharmony_ci			 * non-tuner inputs: autodetection is specific for
44362306a36Sopenharmony_ci			 * TV audio. */
44462306a36Sopenharmony_ci		} else {
44562306a36Sopenharmony_ci			/* Set Path1 to Analog Demod Main Channel */
44662306a36Sopenharmony_ci			cx25840_write4(client, 0x8d0, 0x1f063870);
44762306a36Sopenharmony_ci		}
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	set_audclk_freq(client, state->audclk_freq);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (!is_cx2583x(state)) {
45362306a36Sopenharmony_ci		if (state->aud_input != CX25840_AUDIO_SERIAL) {
45462306a36Sopenharmony_ci			/* When the microcontroller detects the
45562306a36Sopenharmony_ci			 * audio format, it will unmute the lines */
45662306a36Sopenharmony_ci			cx25840_and_or(client, 0x803, ~0x10, 0x10);
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		/* deassert soft reset */
46062306a36Sopenharmony_ci		cx25840_and_or(client, 0x810, ~0x1, 0x00);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		/* Ensure the controller is running when we exit */
46362306a36Sopenharmony_ci		if (is_cx2388x(state) || is_cx231xx(state))
46462306a36Sopenharmony_ci			cx25840_and_or(client, 0x803, ~0x10, 0x10);
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic void set_volume(struct i2c_client *client, int volume)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	int vol;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* Convert the volume to msp3400 values (0-127) */
47362306a36Sopenharmony_ci	vol = volume >> 9;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	/* now scale it up to cx25840 values
47662306a36Sopenharmony_ci	 * -114dB to -96dB maps to 0
47762306a36Sopenharmony_ci	 * this should be 19, but in my testing that was 4dB too loud */
47862306a36Sopenharmony_ci	if (vol <= 23) {
47962306a36Sopenharmony_ci		vol = 0;
48062306a36Sopenharmony_ci	} else {
48162306a36Sopenharmony_ci		vol -= 23;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/* PATH1_VOLUME */
48562306a36Sopenharmony_ci	cx25840_write(client, 0x8d4, 228 - (vol * 2));
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic void set_balance(struct i2c_client *client, int balance)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	int bal = balance >> 8;
49162306a36Sopenharmony_ci	if (bal > 0x80) {
49262306a36Sopenharmony_ci		/* PATH1_BAL_LEFT */
49362306a36Sopenharmony_ci		cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
49462306a36Sopenharmony_ci		/* PATH1_BAL_LEVEL */
49562306a36Sopenharmony_ci		cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
49662306a36Sopenharmony_ci	} else {
49762306a36Sopenharmony_ci		/* PATH1_BAL_LEFT */
49862306a36Sopenharmony_ci		cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
49962306a36Sopenharmony_ci		/* PATH1_BAL_LEVEL */
50062306a36Sopenharmony_ci		cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ciint cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(sd);
50762306a36Sopenharmony_ci	struct cx25840_state *state = to_state(sd);
50862306a36Sopenharmony_ci	int retval;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	if (!is_cx2583x(state))
51162306a36Sopenharmony_ci		cx25840_and_or(client, 0x810, ~0x1, 1);
51262306a36Sopenharmony_ci	if (state->aud_input != CX25840_AUDIO_SERIAL) {
51362306a36Sopenharmony_ci		cx25840_and_or(client, 0x803, ~0x10, 0);
51462306a36Sopenharmony_ci		cx25840_write(client, 0x8d3, 0x1f);
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci	retval = set_audclk_freq(client, freq);
51762306a36Sopenharmony_ci	if (state->aud_input != CX25840_AUDIO_SERIAL)
51862306a36Sopenharmony_ci		cx25840_and_or(client, 0x803, ~0x10, 0x10);
51962306a36Sopenharmony_ci	if (!is_cx2583x(state))
52062306a36Sopenharmony_ci		cx25840_and_or(client, 0x810, ~0x1, 0);
52162306a36Sopenharmony_ci	return retval;
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct v4l2_subdev *sd = to_sd(ctrl);
52762306a36Sopenharmony_ci	struct cx25840_state *state = to_state(sd);
52862306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(sd);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	switch (ctrl->id) {
53162306a36Sopenharmony_ci	case V4L2_CID_AUDIO_VOLUME:
53262306a36Sopenharmony_ci		if (state->mute->val)
53362306a36Sopenharmony_ci			set_volume(client, 0);
53462306a36Sopenharmony_ci		else
53562306a36Sopenharmony_ci			set_volume(client, state->volume->val);
53662306a36Sopenharmony_ci		break;
53762306a36Sopenharmony_ci	case V4L2_CID_AUDIO_BASS:
53862306a36Sopenharmony_ci		/* PATH1_EQ_BASS_VOL */
53962306a36Sopenharmony_ci		cx25840_and_or(client, 0x8d9, ~0x3f,
54062306a36Sopenharmony_ci					48 - (ctrl->val * 48 / 0xffff));
54162306a36Sopenharmony_ci		break;
54262306a36Sopenharmony_ci	case V4L2_CID_AUDIO_TREBLE:
54362306a36Sopenharmony_ci		/* PATH1_EQ_TREBLE_VOL */
54462306a36Sopenharmony_ci		cx25840_and_or(client, 0x8db, ~0x3f,
54562306a36Sopenharmony_ci					48 - (ctrl->val * 48 / 0xffff));
54662306a36Sopenharmony_ci		break;
54762306a36Sopenharmony_ci	case V4L2_CID_AUDIO_BALANCE:
54862306a36Sopenharmony_ci		set_balance(client, ctrl->val);
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci	default:
55162306a36Sopenharmony_ci		return -EINVAL;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci	return 0;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ciconst struct v4l2_ctrl_ops cx25840_audio_ctrl_ops = {
55762306a36Sopenharmony_ci	.s_ctrl = cx25840_audio_s_ctrl,
55862306a36Sopenharmony_ci};
559