xref: /openbmc/linux/drivers/media/i2c/max2175.c (revision aaeb31c0)
1d9d94479SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
2b47b79d8SRamesh Shanmugasundaram /*
3b47b79d8SRamesh Shanmugasundaram  * Maxim Integrated MAX2175 RF to Bits tuner driver
4b47b79d8SRamesh Shanmugasundaram  *
5b47b79d8SRamesh Shanmugasundaram  * This driver & most of the hard coded values are based on the reference
6b47b79d8SRamesh Shanmugasundaram  * application delivered by Maxim for this device.
7b47b79d8SRamesh Shanmugasundaram  *
8b47b79d8SRamesh Shanmugasundaram  * Copyright (C) 2016 Maxim Integrated Products
9b47b79d8SRamesh Shanmugasundaram  * Copyright (C) 2017 Renesas Electronics Corporation
10b47b79d8SRamesh Shanmugasundaram  */
11b47b79d8SRamesh Shanmugasundaram 
12b47b79d8SRamesh Shanmugasundaram #include <linux/clk.h>
13b47b79d8SRamesh Shanmugasundaram #include <linux/delay.h>
14b47b79d8SRamesh Shanmugasundaram #include <linux/errno.h>
15b47b79d8SRamesh Shanmugasundaram #include <linux/i2c.h>
16b47b79d8SRamesh Shanmugasundaram #include <linux/kernel.h>
17b47b79d8SRamesh Shanmugasundaram #include <linux/math64.h>
18b47b79d8SRamesh Shanmugasundaram #include <linux/max2175.h>
19b47b79d8SRamesh Shanmugasundaram #include <linux/module.h>
20b47b79d8SRamesh Shanmugasundaram #include <linux/of.h>
21b47b79d8SRamesh Shanmugasundaram #include <linux/regmap.h>
22b47b79d8SRamesh Shanmugasundaram #include <linux/slab.h>
23b47b79d8SRamesh Shanmugasundaram #include <media/v4l2-ctrls.h>
24b47b79d8SRamesh Shanmugasundaram #include <media/v4l2-device.h>
25b47b79d8SRamesh Shanmugasundaram 
26b47b79d8SRamesh Shanmugasundaram #include "max2175.h"
27b47b79d8SRamesh Shanmugasundaram 
28b47b79d8SRamesh Shanmugasundaram #define DRIVER_NAME "max2175"
29b47b79d8SRamesh Shanmugasundaram 
30b47b79d8SRamesh Shanmugasundaram #define mxm_dbg(ctx, fmt, arg...) dev_dbg(&ctx->client->dev, fmt, ## arg)
31b47b79d8SRamesh Shanmugasundaram #define mxm_err(ctx, fmt, arg...) dev_err(&ctx->client->dev, fmt, ## arg)
32b47b79d8SRamesh Shanmugasundaram 
33b47b79d8SRamesh Shanmugasundaram /* Rx mode */
34b47b79d8SRamesh Shanmugasundaram struct max2175_rxmode {
35b47b79d8SRamesh Shanmugasundaram 	enum max2175_band band;		/* Associated band */
36b47b79d8SRamesh Shanmugasundaram 	u32 freq;			/* Default freq in Hz */
37b47b79d8SRamesh Shanmugasundaram 	u8 i2s_word_size;		/* Bit value */
38b47b79d8SRamesh Shanmugasundaram };
39b47b79d8SRamesh Shanmugasundaram 
40b47b79d8SRamesh Shanmugasundaram /* Register map to define preset values */
41b47b79d8SRamesh Shanmugasundaram struct max2175_reg_map {
42b47b79d8SRamesh Shanmugasundaram 	u8 idx;				/* Register index */
43b47b79d8SRamesh Shanmugasundaram 	u8 val;				/* Register value */
44b47b79d8SRamesh Shanmugasundaram };
45b47b79d8SRamesh Shanmugasundaram 
46b47b79d8SRamesh Shanmugasundaram static const struct max2175_rxmode eu_rx_modes[] = {
47b47b79d8SRamesh Shanmugasundaram 	/* EU modes */
48b47b79d8SRamesh Shanmugasundaram 	[MAX2175_EU_FM_1_2] = { MAX2175_BAND_FM, 98256000, 1 },
49b47b79d8SRamesh Shanmugasundaram 	[MAX2175_DAB_1_2]   = { MAX2175_BAND_VHF, 182640000, 0 },
50b47b79d8SRamesh Shanmugasundaram };
51b47b79d8SRamesh Shanmugasundaram 
52b47b79d8SRamesh Shanmugasundaram static const struct max2175_rxmode na_rx_modes[] = {
53b47b79d8SRamesh Shanmugasundaram 	/* NA modes */
54b47b79d8SRamesh Shanmugasundaram 	[MAX2175_NA_FM_1_0] = { MAX2175_BAND_FM, 98255520, 1 },
55b47b79d8SRamesh Shanmugasundaram 	[MAX2175_NA_FM_2_0] = { MAX2175_BAND_FM, 98255520, 6 },
56b47b79d8SRamesh Shanmugasundaram };
57b47b79d8SRamesh Shanmugasundaram 
58b47b79d8SRamesh Shanmugasundaram /*
59b47b79d8SRamesh Shanmugasundaram  * Preset values:
60b47b79d8SRamesh Shanmugasundaram  * Based on Maxim MAX2175 Register Table revision: 130p10
61b47b79d8SRamesh Shanmugasundaram  */
62b47b79d8SRamesh Shanmugasundaram static const u8 full_fm_eu_1p0[] = {
63b47b79d8SRamesh Shanmugasundaram 	0x15, 0x04, 0xb8, 0xe3, 0x35, 0x18, 0x7c, 0x00,
64b47b79d8SRamesh Shanmugasundaram 	0x00, 0x7d, 0x40, 0x08, 0x70, 0x7a, 0x88, 0x91,
65b47b79d8SRamesh Shanmugasundaram 	0x61, 0x61, 0x61, 0x61, 0x5a, 0x0f, 0x34, 0x1c,
66b47b79d8SRamesh Shanmugasundaram 	0x14, 0x88, 0x33, 0x02, 0x00, 0x09, 0x00, 0x65,
67b47b79d8SRamesh Shanmugasundaram 	0x9f, 0x2b, 0x80, 0x00, 0x95, 0x05, 0x2c, 0x00,
68b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
69b47b79d8SRamesh Shanmugasundaram 	0x4a, 0x08, 0xa8, 0x0e, 0x0e, 0x2f, 0x7e, 0x00,
70b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x5e, 0xa9,
72b47b79d8SRamesh Shanmugasundaram 	0xae, 0xbb, 0x57, 0x18, 0x3b, 0x03, 0x3b, 0x64,
73b47b79d8SRamesh Shanmugasundaram 	0x40, 0x60, 0x00, 0x2a, 0xbf, 0x3f, 0xff, 0x9f,
74b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
75b47b79d8SRamesh Shanmugasundaram 	0xff, 0xfc, 0xef, 0x1c, 0x40, 0x00, 0x00, 0x02,
76b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
77b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x40, 0x00,
78b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00,
79b47b79d8SRamesh Shanmugasundaram 	0x00, 0x47, 0x00, 0x00, 0x11, 0x3f, 0x22, 0x00,
80b47b79d8SRamesh Shanmugasundaram 	0xf1, 0x00, 0x41, 0x03, 0xb0, 0x00, 0x00, 0x00,
81b47b79d8SRamesh Shanmugasundaram 	0x1b,
82b47b79d8SRamesh Shanmugasundaram };
83b47b79d8SRamesh Shanmugasundaram 
84b47b79d8SRamesh Shanmugasundaram static const u8 full_fm_na_1p0[] = {
85b47b79d8SRamesh Shanmugasundaram 	0x13, 0x08, 0x8d, 0xc0, 0x35, 0x18, 0x7d, 0x3f,
86b47b79d8SRamesh Shanmugasundaram 	0x7d, 0x75, 0x40, 0x08, 0x70, 0x7a, 0x88, 0x91,
87b47b79d8SRamesh Shanmugasundaram 	0x61, 0x61, 0x61, 0x61, 0x5c, 0x0f, 0x34, 0x1c,
88b47b79d8SRamesh Shanmugasundaram 	0x14, 0x88, 0x33, 0x02, 0x00, 0x01, 0x00, 0x65,
89b47b79d8SRamesh Shanmugasundaram 	0x9f, 0x2b, 0x80, 0x00, 0x95, 0x05, 0x2c, 0x00,
90b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
91b47b79d8SRamesh Shanmugasundaram 	0x4a, 0x08, 0xa8, 0x0e, 0x0e, 0xaf, 0x7e, 0x00,
92b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x5e, 0xa9,
94b47b79d8SRamesh Shanmugasundaram 	0xae, 0xbb, 0x57, 0x18, 0x3b, 0x03, 0x3b, 0x64,
95b47b79d8SRamesh Shanmugasundaram 	0x40, 0x60, 0x00, 0x2a, 0xbf, 0x3f, 0xff, 0x9f,
96b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
97b47b79d8SRamesh Shanmugasundaram 	0xff, 0xfc, 0xef, 0x1c, 0x40, 0x00, 0x00, 0x02,
98b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
99b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x40, 0x00,
100b47b79d8SRamesh Shanmugasundaram 	0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00,
101b47b79d8SRamesh Shanmugasundaram 	0x00, 0x35, 0x00, 0x00, 0x11, 0x3f, 0x22, 0x00,
102b47b79d8SRamesh Shanmugasundaram 	0xf1, 0x00, 0x41, 0x03, 0xb0, 0x00, 0x00, 0x00,
103b47b79d8SRamesh Shanmugasundaram 	0x1b,
104b47b79d8SRamesh Shanmugasundaram };
105b47b79d8SRamesh Shanmugasundaram 
106b47b79d8SRamesh Shanmugasundaram /* DAB1.2 settings */
107b47b79d8SRamesh Shanmugasundaram static const struct max2175_reg_map dab12_map[] = {
108b47b79d8SRamesh Shanmugasundaram 	{ 0x01, 0x13 }, { 0x02, 0x0d }, { 0x03, 0x15 }, { 0x04, 0x55 },
109b47b79d8SRamesh Shanmugasundaram 	{ 0x05, 0x0a }, { 0x06, 0xa0 }, { 0x07, 0x40 }, { 0x08, 0x00 },
110b47b79d8SRamesh Shanmugasundaram 	{ 0x09, 0x00 }, { 0x0a, 0x7d }, { 0x0b, 0x4a }, { 0x0c, 0x28 },
111b47b79d8SRamesh Shanmugasundaram 	{ 0x0e, 0x43 }, { 0x0f, 0xb5 }, { 0x10, 0x31 }, { 0x11, 0x9e },
112b47b79d8SRamesh Shanmugasundaram 	{ 0x12, 0x68 }, { 0x13, 0x9e }, { 0x14, 0x68 }, { 0x15, 0x58 },
113b47b79d8SRamesh Shanmugasundaram 	{ 0x16, 0x2f }, { 0x17, 0x3f }, { 0x18, 0x40 }, { 0x1a, 0x88 },
114b47b79d8SRamesh Shanmugasundaram 	{ 0x1b, 0xaa }, { 0x1c, 0x9a }, { 0x1d, 0x00 }, { 0x1e, 0x00 },
115b47b79d8SRamesh Shanmugasundaram 	{ 0x23, 0x80 }, { 0x24, 0x00 }, { 0x25, 0x00 }, { 0x26, 0x00 },
116b47b79d8SRamesh Shanmugasundaram 	{ 0x27, 0x00 }, { 0x32, 0x08 }, { 0x33, 0xf8 }, { 0x36, 0x2d },
117b47b79d8SRamesh Shanmugasundaram 	{ 0x37, 0x7e }, { 0x55, 0xaf }, { 0x56, 0x3f }, { 0x57, 0xf8 },
118b47b79d8SRamesh Shanmugasundaram 	{ 0x58, 0x99 }, { 0x76, 0x00 }, { 0x77, 0x00 }, { 0x78, 0x02 },
119b47b79d8SRamesh Shanmugasundaram 	{ 0x79, 0x40 }, { 0x82, 0x00 }, { 0x83, 0x00 }, { 0x85, 0x00 },
120b47b79d8SRamesh Shanmugasundaram 	{ 0x86, 0x20 },
121b47b79d8SRamesh Shanmugasundaram };
122b47b79d8SRamesh Shanmugasundaram 
123b47b79d8SRamesh Shanmugasundaram /* EU FM 1.2 settings */
124b47b79d8SRamesh Shanmugasundaram static const struct max2175_reg_map fmeu1p2_map[] = {
125b47b79d8SRamesh Shanmugasundaram 	{ 0x01, 0x15 }, { 0x02, 0x04 }, { 0x03, 0xb8 }, { 0x04, 0xe3 },
126b47b79d8SRamesh Shanmugasundaram 	{ 0x05, 0x35 }, { 0x06, 0x18 }, { 0x07, 0x7c }, { 0x08, 0x00 },
127b47b79d8SRamesh Shanmugasundaram 	{ 0x09, 0x00 }, { 0x0a, 0x73 }, { 0x0b, 0x40 }, { 0x0c, 0x08 },
128b47b79d8SRamesh Shanmugasundaram 	{ 0x0e, 0x7a }, { 0x0f, 0x88 }, { 0x10, 0x91 }, { 0x11, 0x61 },
129b47b79d8SRamesh Shanmugasundaram 	{ 0x12, 0x61 }, { 0x13, 0x61 }, { 0x14, 0x61 }, { 0x15, 0x5a },
130b47b79d8SRamesh Shanmugasundaram 	{ 0x16, 0x0f }, { 0x17, 0x34 }, { 0x18, 0x1c }, { 0x1a, 0x88 },
131b47b79d8SRamesh Shanmugasundaram 	{ 0x1b, 0x33 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x1e, 0x01 },
132b47b79d8SRamesh Shanmugasundaram 	{ 0x23, 0x80 }, { 0x24, 0x00 }, { 0x25, 0x95 }, { 0x26, 0x05 },
133b47b79d8SRamesh Shanmugasundaram 	{ 0x27, 0x2c }, { 0x32, 0x08 }, { 0x33, 0xa8 }, { 0x36, 0x2f },
134b47b79d8SRamesh Shanmugasundaram 	{ 0x37, 0x7e }, { 0x55, 0xbf }, { 0x56, 0x3f }, { 0x57, 0xff },
135b47b79d8SRamesh Shanmugasundaram 	{ 0x58, 0x9f }, { 0x76, 0xac }, { 0x77, 0x40 }, { 0x78, 0x00 },
136b47b79d8SRamesh Shanmugasundaram 	{ 0x79, 0x00 }, { 0x82, 0x47 }, { 0x83, 0x00 }, { 0x85, 0x11 },
137b47b79d8SRamesh Shanmugasundaram 	{ 0x86, 0x3f },
138b47b79d8SRamesh Shanmugasundaram };
139b47b79d8SRamesh Shanmugasundaram 
140b47b79d8SRamesh Shanmugasundaram /* FM NA 1.0 settings */
141b47b79d8SRamesh Shanmugasundaram static const struct max2175_reg_map fmna1p0_map[] = {
142b47b79d8SRamesh Shanmugasundaram 	{ 0x01, 0x13 }, { 0x02, 0x08 }, { 0x03, 0x8d }, { 0x04, 0xc0 },
143b47b79d8SRamesh Shanmugasundaram 	{ 0x05, 0x35 }, { 0x06, 0x18 }, { 0x07, 0x7d }, { 0x08, 0x3f },
144b47b79d8SRamesh Shanmugasundaram 	{ 0x09, 0x7d }, { 0x0a, 0x75 }, { 0x0b, 0x40 }, { 0x0c, 0x08 },
145b47b79d8SRamesh Shanmugasundaram 	{ 0x0e, 0x7a }, { 0x0f, 0x88 }, { 0x10, 0x91 }, { 0x11, 0x61 },
146b47b79d8SRamesh Shanmugasundaram 	{ 0x12, 0x61 }, { 0x13, 0x61 }, { 0x14, 0x61 }, { 0x15, 0x5c },
147b47b79d8SRamesh Shanmugasundaram 	{ 0x16, 0x0f }, { 0x17, 0x34 }, { 0x18, 0x1c }, { 0x1a, 0x88 },
148b47b79d8SRamesh Shanmugasundaram 	{ 0x1b, 0x33 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x1e, 0x01 },
149b47b79d8SRamesh Shanmugasundaram 	{ 0x23, 0x80 }, { 0x24, 0x00 }, { 0x25, 0x95 }, { 0x26, 0x05 },
150b47b79d8SRamesh Shanmugasundaram 	{ 0x27, 0x2c }, { 0x32, 0x08 }, { 0x33, 0xa8 }, { 0x36, 0xaf },
151b47b79d8SRamesh Shanmugasundaram 	{ 0x37, 0x7e }, { 0x55, 0xbf }, { 0x56, 0x3f }, { 0x57, 0xff },
152b47b79d8SRamesh Shanmugasundaram 	{ 0x58, 0x9f }, { 0x76, 0xa6 }, { 0x77, 0x40 }, { 0x78, 0x00 },
153b47b79d8SRamesh Shanmugasundaram 	{ 0x79, 0x00 }, { 0x82, 0x35 }, { 0x83, 0x00 }, { 0x85, 0x11 },
154b47b79d8SRamesh Shanmugasundaram 	{ 0x86, 0x3f },
155b47b79d8SRamesh Shanmugasundaram };
156b47b79d8SRamesh Shanmugasundaram 
157b47b79d8SRamesh Shanmugasundaram /* FM NA 2.0 settings */
158b47b79d8SRamesh Shanmugasundaram static const struct max2175_reg_map fmna2p0_map[] = {
159b47b79d8SRamesh Shanmugasundaram 	{ 0x01, 0x13 }, { 0x02, 0x08 }, { 0x03, 0x8d }, { 0x04, 0xc0 },
160b47b79d8SRamesh Shanmugasundaram 	{ 0x05, 0x35 }, { 0x06, 0x18 }, { 0x07, 0x7c }, { 0x08, 0x54 },
161b47b79d8SRamesh Shanmugasundaram 	{ 0x09, 0xa7 }, { 0x0a, 0x55 }, { 0x0b, 0x42 }, { 0x0c, 0x48 },
162b47b79d8SRamesh Shanmugasundaram 	{ 0x0e, 0x7a }, { 0x0f, 0x88 }, { 0x10, 0x91 }, { 0x11, 0x61 },
163b47b79d8SRamesh Shanmugasundaram 	{ 0x12, 0x61 }, { 0x13, 0x61 }, { 0x14, 0x61 }, { 0x15, 0x5c },
164b47b79d8SRamesh Shanmugasundaram 	{ 0x16, 0x0f }, { 0x17, 0x34 }, { 0x18, 0x1c }, { 0x1a, 0x88 },
165b47b79d8SRamesh Shanmugasundaram 	{ 0x1b, 0x33 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x1e, 0x01 },
166b47b79d8SRamesh Shanmugasundaram 	{ 0x23, 0x80 }, { 0x24, 0x00 }, { 0x25, 0x95 }, { 0x26, 0x05 },
167b47b79d8SRamesh Shanmugasundaram 	{ 0x27, 0x2c }, { 0x32, 0x08 }, { 0x33, 0xa8 }, { 0x36, 0xaf },
168b47b79d8SRamesh Shanmugasundaram 	{ 0x37, 0x7e }, { 0x55, 0xbf }, { 0x56, 0x3f }, { 0x57, 0xff },
169b47b79d8SRamesh Shanmugasundaram 	{ 0x58, 0x9f }, { 0x76, 0xac }, { 0x77, 0xc0 }, { 0x78, 0x00 },
170b47b79d8SRamesh Shanmugasundaram 	{ 0x79, 0x00 }, { 0x82, 0x6b }, { 0x83, 0x00 }, { 0x85, 0x11 },
171b47b79d8SRamesh Shanmugasundaram 	{ 0x86, 0x3f },
172b47b79d8SRamesh Shanmugasundaram };
173b47b79d8SRamesh Shanmugasundaram 
174b47b79d8SRamesh Shanmugasundaram static const u16 ch_coeff_dab1[] = {
175b47b79d8SRamesh Shanmugasundaram 	0x001c, 0x0007, 0xffcd, 0x0056, 0xffa4, 0x0033, 0x0027, 0xff61,
176b47b79d8SRamesh Shanmugasundaram 	0x010e, 0xfec0, 0x0106, 0xffb8, 0xff1c, 0x023c, 0xfcb2, 0x039b,
177b47b79d8SRamesh Shanmugasundaram 	0xfd4e, 0x0055, 0x036a, 0xf7de, 0x0d21, 0xee72, 0x1499, 0x6a51,
178b47b79d8SRamesh Shanmugasundaram };
179b47b79d8SRamesh Shanmugasundaram 
180b47b79d8SRamesh Shanmugasundaram static const u16 ch_coeff_fmeu[] = {
181b47b79d8SRamesh Shanmugasundaram 	0x0000, 0xffff, 0x0001, 0x0002, 0xfffa, 0xffff, 0x0015, 0xffec,
182b47b79d8SRamesh Shanmugasundaram 	0xffde, 0x0054, 0xfff9, 0xff52, 0x00b8, 0x00a2, 0xfe0a, 0x00af,
183b47b79d8SRamesh Shanmugasundaram 	0x02e3, 0xfc14, 0xfe89, 0x089d, 0xfa2e, 0xf30f, 0x25be, 0x4eb6,
184b47b79d8SRamesh Shanmugasundaram };
185b47b79d8SRamesh Shanmugasundaram 
186b47b79d8SRamesh Shanmugasundaram static const u16 eq_coeff_fmeu1_ra02_m6db[] = {
187b47b79d8SRamesh Shanmugasundaram 	0x0040, 0xffc6, 0xfffa, 0x002c, 0x000d, 0xff90, 0x0037, 0x006e,
188b47b79d8SRamesh Shanmugasundaram 	0xffc0, 0xff5b, 0x006a, 0x00f0, 0xff57, 0xfe94, 0x0112, 0x0252,
189b47b79d8SRamesh Shanmugasundaram 	0xfe0c, 0xfc6a, 0x0385, 0x0553, 0xfa49, 0xf789, 0x0b91, 0x1a10,
190b47b79d8SRamesh Shanmugasundaram };
191b47b79d8SRamesh Shanmugasundaram 
192b47b79d8SRamesh Shanmugasundaram static const u16 ch_coeff_fmna[] = {
193b47b79d8SRamesh Shanmugasundaram 	0x0001, 0x0003, 0xfffe, 0xfff4, 0x0000, 0x001f, 0x000c, 0xffbc,
194b47b79d8SRamesh Shanmugasundaram 	0xffd3, 0x007d, 0x0075, 0xff33, 0xff01, 0x0131, 0x01ef, 0xfe60,
195b47b79d8SRamesh Shanmugasundaram 	0xfc7a, 0x020e, 0x0656, 0xfd94, 0xf395, 0x02ab, 0x2857, 0x3d3f,
196b47b79d8SRamesh Shanmugasundaram };
197b47b79d8SRamesh Shanmugasundaram 
198b47b79d8SRamesh Shanmugasundaram static const u16 eq_coeff_fmna1_ra02_m6db[] = {
199b47b79d8SRamesh Shanmugasundaram 	0xfff1, 0xffe1, 0xffef, 0x000e, 0x0030, 0x002f, 0xfff6, 0xffa7,
200b47b79d8SRamesh Shanmugasundaram 	0xff9d, 0x000a, 0x00a2, 0x00b5, 0xffea, 0xfed9, 0xfec5, 0x003d,
201b47b79d8SRamesh Shanmugasundaram 	0x0217, 0x021b, 0xff5a, 0xfc2b, 0xfcbd, 0x02c4, 0x0ac3, 0x0e85,
202b47b79d8SRamesh Shanmugasundaram };
203b47b79d8SRamesh Shanmugasundaram 
204b47b79d8SRamesh Shanmugasundaram static const u8 adc_presets[2][23] = {
205b47b79d8SRamesh Shanmugasundaram 	{
206b47b79d8SRamesh Shanmugasundaram 		0x83, 0x00, 0xcf, 0xb4, 0x0f, 0x2c, 0x0c, 0x49,
207b47b79d8SRamesh Shanmugasundaram 		0x00, 0x00, 0x00, 0x8c,	0x02, 0x02, 0x00, 0x04,
208b47b79d8SRamesh Shanmugasundaram 		0xec, 0x82, 0x4b, 0xcc, 0x01, 0x88, 0x0c,
209b47b79d8SRamesh Shanmugasundaram 	},
210b47b79d8SRamesh Shanmugasundaram 	{
211b47b79d8SRamesh Shanmugasundaram 		0x83, 0x00, 0xcf, 0xb4,	0x0f, 0x2c, 0x0c, 0x49,
212b47b79d8SRamesh Shanmugasundaram 		0x00, 0x00, 0x00, 0x8c,	0x02, 0x20, 0x33, 0x8c,
213b47b79d8SRamesh Shanmugasundaram 		0x57, 0xd7, 0x59, 0xb7,	0x65, 0x0e, 0x0c,
214b47b79d8SRamesh Shanmugasundaram 	},
215b47b79d8SRamesh Shanmugasundaram };
216b47b79d8SRamesh Shanmugasundaram 
217b47b79d8SRamesh Shanmugasundaram /* Tuner bands */
218b47b79d8SRamesh Shanmugasundaram static const struct v4l2_frequency_band eu_bands_rf = {
219b47b79d8SRamesh Shanmugasundaram 	.tuner = 0,
220b47b79d8SRamesh Shanmugasundaram 	.type = V4L2_TUNER_RF,
221b47b79d8SRamesh Shanmugasundaram 	.index = 0,
222b47b79d8SRamesh Shanmugasundaram 	.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
223b47b79d8SRamesh Shanmugasundaram 	.rangelow   = 65000000,
224b47b79d8SRamesh Shanmugasundaram 	.rangehigh  = 240000000,
225b47b79d8SRamesh Shanmugasundaram };
226b47b79d8SRamesh Shanmugasundaram 
227b47b79d8SRamesh Shanmugasundaram static const struct v4l2_frequency_band na_bands_rf = {
228b47b79d8SRamesh Shanmugasundaram 	.tuner = 0,
229b47b79d8SRamesh Shanmugasundaram 	.type = V4L2_TUNER_RF,
230b47b79d8SRamesh Shanmugasundaram 	.index = 0,
231b47b79d8SRamesh Shanmugasundaram 	.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
232b47b79d8SRamesh Shanmugasundaram 	.rangelow   = 65000000,
233b47b79d8SRamesh Shanmugasundaram 	.rangehigh  = 108000000,
234b47b79d8SRamesh Shanmugasundaram };
235b47b79d8SRamesh Shanmugasundaram 
236b47b79d8SRamesh Shanmugasundaram /* Regmap settings */
237b47b79d8SRamesh Shanmugasundaram static const struct regmap_range max2175_regmap_volatile_range[] = {
238b47b79d8SRamesh Shanmugasundaram 	regmap_reg_range(0x30, 0x35),
239b47b79d8SRamesh Shanmugasundaram 	regmap_reg_range(0x3a, 0x45),
240b47b79d8SRamesh Shanmugasundaram 	regmap_reg_range(0x59, 0x5e),
241b47b79d8SRamesh Shanmugasundaram 	regmap_reg_range(0x73, 0x75),
242b47b79d8SRamesh Shanmugasundaram };
243b47b79d8SRamesh Shanmugasundaram 
244b47b79d8SRamesh Shanmugasundaram static const struct regmap_access_table max2175_volatile_regs = {
245b47b79d8SRamesh Shanmugasundaram 	.yes_ranges = max2175_regmap_volatile_range,
246b47b79d8SRamesh Shanmugasundaram 	.n_yes_ranges = ARRAY_SIZE(max2175_regmap_volatile_range),
247b47b79d8SRamesh Shanmugasundaram };
248b47b79d8SRamesh Shanmugasundaram 
249b47b79d8SRamesh Shanmugasundaram static const struct reg_default max2175_reg_defaults[] = {
250b47b79d8SRamesh Shanmugasundaram 	{ 0x00, 0x07},
251b47b79d8SRamesh Shanmugasundaram };
252b47b79d8SRamesh Shanmugasundaram 
253b47b79d8SRamesh Shanmugasundaram static const struct regmap_config max2175_regmap_config = {
254b47b79d8SRamesh Shanmugasundaram 	.reg_bits = 8,
255b47b79d8SRamesh Shanmugasundaram 	.val_bits = 8,
256b47b79d8SRamesh Shanmugasundaram 	.max_register = 0xff,
257b47b79d8SRamesh Shanmugasundaram 	.reg_defaults = max2175_reg_defaults,
258b47b79d8SRamesh Shanmugasundaram 	.num_reg_defaults = ARRAY_SIZE(max2175_reg_defaults),
259b47b79d8SRamesh Shanmugasundaram 	.volatile_table = &max2175_volatile_regs,
26042a55435SMark Brown 	.cache_type = REGCACHE_RBTREE,
261b47b79d8SRamesh Shanmugasundaram };
262b47b79d8SRamesh Shanmugasundaram 
263b47b79d8SRamesh Shanmugasundaram struct max2175 {
264b47b79d8SRamesh Shanmugasundaram 	struct v4l2_subdev sd;		/* Sub-device */
265b47b79d8SRamesh Shanmugasundaram 	struct i2c_client *client;	/* I2C client */
266b47b79d8SRamesh Shanmugasundaram 
267b47b79d8SRamesh Shanmugasundaram 	/* Controls */
268b47b79d8SRamesh Shanmugasundaram 	struct v4l2_ctrl_handler ctrl_hdl;
269b47b79d8SRamesh Shanmugasundaram 	struct v4l2_ctrl *lna_gain;	/* LNA gain value */
270b47b79d8SRamesh Shanmugasundaram 	struct v4l2_ctrl *if_gain;	/* I/F gain value */
271b47b79d8SRamesh Shanmugasundaram 	struct v4l2_ctrl *pll_lock;	/* PLL lock */
272b47b79d8SRamesh Shanmugasundaram 	struct v4l2_ctrl *i2s_en;	/* I2S output enable */
273b47b79d8SRamesh Shanmugasundaram 	struct v4l2_ctrl *hsls;		/* High-side/Low-side polarity */
274b47b79d8SRamesh Shanmugasundaram 	struct v4l2_ctrl *rx_mode;	/* Receive mode */
275b47b79d8SRamesh Shanmugasundaram 
276b47b79d8SRamesh Shanmugasundaram 	/* Regmap */
277b47b79d8SRamesh Shanmugasundaram 	struct regmap *regmap;
278b47b79d8SRamesh Shanmugasundaram 
279b47b79d8SRamesh Shanmugasundaram 	/* Cached configuration */
280b47b79d8SRamesh Shanmugasundaram 	u32 freq;			/* Tuned freq In Hz */
281b47b79d8SRamesh Shanmugasundaram 	const struct max2175_rxmode *rx_modes;		/* EU or NA modes */
282b47b79d8SRamesh Shanmugasundaram 	const struct v4l2_frequency_band *bands_rf;	/* EU or NA bands */
283b47b79d8SRamesh Shanmugasundaram 
284b47b79d8SRamesh Shanmugasundaram 	/* Device settings */
285b47b79d8SRamesh Shanmugasundaram 	unsigned long xtal_freq;	/* Ref Oscillator freq in Hz */
286b47b79d8SRamesh Shanmugasundaram 	u32 decim_ratio;
287b47b79d8SRamesh Shanmugasundaram 	bool master;			/* Master/Slave */
288b47b79d8SRamesh Shanmugasundaram 	bool am_hiz;			/* AM Hi-Z filter */
289b47b79d8SRamesh Shanmugasundaram 
290b47b79d8SRamesh Shanmugasundaram 	/* ROM values */
291b47b79d8SRamesh Shanmugasundaram 	u8 rom_bbf_bw_am;
292b47b79d8SRamesh Shanmugasundaram 	u8 rom_bbf_bw_fm;
293b47b79d8SRamesh Shanmugasundaram 	u8 rom_bbf_bw_dab;
294b47b79d8SRamesh Shanmugasundaram 
295b47b79d8SRamesh Shanmugasundaram 	/* Driver private variables */
296b47b79d8SRamesh Shanmugasundaram 	bool mode_resolved;		/* Flag to sanity check settings */
297b47b79d8SRamesh Shanmugasundaram };
298b47b79d8SRamesh Shanmugasundaram 
max2175_from_sd(struct v4l2_subdev * sd)299b47b79d8SRamesh Shanmugasundaram static inline struct max2175 *max2175_from_sd(struct v4l2_subdev *sd)
300b47b79d8SRamesh Shanmugasundaram {
301b47b79d8SRamesh Shanmugasundaram 	return container_of(sd, struct max2175, sd);
302b47b79d8SRamesh Shanmugasundaram }
303b47b79d8SRamesh Shanmugasundaram 
max2175_from_ctrl_hdl(struct v4l2_ctrl_handler * h)304b47b79d8SRamesh Shanmugasundaram static inline struct max2175 *max2175_from_ctrl_hdl(struct v4l2_ctrl_handler *h)
305b47b79d8SRamesh Shanmugasundaram {
306b47b79d8SRamesh Shanmugasundaram 	return container_of(h, struct max2175, ctrl_hdl);
307b47b79d8SRamesh Shanmugasundaram }
308b47b79d8SRamesh Shanmugasundaram 
309b47b79d8SRamesh Shanmugasundaram /* Get bitval of a given val */
max2175_get_bitval(u8 val,u8 msb,u8 lsb)310b47b79d8SRamesh Shanmugasundaram static inline u8 max2175_get_bitval(u8 val, u8 msb, u8 lsb)
311b47b79d8SRamesh Shanmugasundaram {
312b47b79d8SRamesh Shanmugasundaram 	return (val & GENMASK(msb, lsb)) >> lsb;
313b47b79d8SRamesh Shanmugasundaram }
314b47b79d8SRamesh Shanmugasundaram 
315b47b79d8SRamesh Shanmugasundaram /* Read/Write bit(s) on top of regmap */
max2175_read(struct max2175 * ctx,u8 idx,u8 * val)316b47b79d8SRamesh Shanmugasundaram static int max2175_read(struct max2175 *ctx, u8 idx, u8 *val)
317b47b79d8SRamesh Shanmugasundaram {
318b47b79d8SRamesh Shanmugasundaram 	u32 regval;
319b47b79d8SRamesh Shanmugasundaram 	int ret;
320b47b79d8SRamesh Shanmugasundaram 
321b47b79d8SRamesh Shanmugasundaram 	ret = regmap_read(ctx->regmap, idx, &regval);
322b47b79d8SRamesh Shanmugasundaram 	if (ret)
323b47b79d8SRamesh Shanmugasundaram 		mxm_err(ctx, "read ret(%d): idx 0x%02x\n", ret, idx);
324b47b79d8SRamesh Shanmugasundaram 	else
325b47b79d8SRamesh Shanmugasundaram 		*val = regval;
326b47b79d8SRamesh Shanmugasundaram 
327b47b79d8SRamesh Shanmugasundaram 	return ret;
328b47b79d8SRamesh Shanmugasundaram }
329b47b79d8SRamesh Shanmugasundaram 
max2175_write(struct max2175 * ctx,u8 idx,u8 val)330b47b79d8SRamesh Shanmugasundaram static int max2175_write(struct max2175 *ctx, u8 idx, u8 val)
331b47b79d8SRamesh Shanmugasundaram {
332b47b79d8SRamesh Shanmugasundaram 	int ret;
333b47b79d8SRamesh Shanmugasundaram 
334b47b79d8SRamesh Shanmugasundaram 	ret = regmap_write(ctx->regmap, idx, val);
335b47b79d8SRamesh Shanmugasundaram 	if (ret)
336b47b79d8SRamesh Shanmugasundaram 		mxm_err(ctx, "write ret(%d): idx 0x%02x val 0x%02x\n",
337b47b79d8SRamesh Shanmugasundaram 			ret, idx, val);
338b47b79d8SRamesh Shanmugasundaram 
339b47b79d8SRamesh Shanmugasundaram 	return ret;
340b47b79d8SRamesh Shanmugasundaram }
341b47b79d8SRamesh Shanmugasundaram 
max2175_read_bits(struct max2175 * ctx,u8 idx,u8 msb,u8 lsb)342b47b79d8SRamesh Shanmugasundaram static u8 max2175_read_bits(struct max2175 *ctx, u8 idx, u8 msb, u8 lsb)
343b47b79d8SRamesh Shanmugasundaram {
344b47b79d8SRamesh Shanmugasundaram 	u8 val;
345b47b79d8SRamesh Shanmugasundaram 
346b47b79d8SRamesh Shanmugasundaram 	if (max2175_read(ctx, idx, &val))
347b47b79d8SRamesh Shanmugasundaram 		return 0;
348b47b79d8SRamesh Shanmugasundaram 
349b47b79d8SRamesh Shanmugasundaram 	return max2175_get_bitval(val, msb, lsb);
350b47b79d8SRamesh Shanmugasundaram }
351b47b79d8SRamesh Shanmugasundaram 
max2175_write_bits(struct max2175 * ctx,u8 idx,u8 msb,u8 lsb,u8 newval)352b47b79d8SRamesh Shanmugasundaram static int max2175_write_bits(struct max2175 *ctx, u8 idx,
353b47b79d8SRamesh Shanmugasundaram 			     u8 msb, u8 lsb, u8 newval)
354b47b79d8SRamesh Shanmugasundaram {
355b47b79d8SRamesh Shanmugasundaram 	int ret = regmap_update_bits(ctx->regmap, idx, GENMASK(msb, lsb),
356b47b79d8SRamesh Shanmugasundaram 				     newval << lsb);
357b47b79d8SRamesh Shanmugasundaram 
358b47b79d8SRamesh Shanmugasundaram 	if (ret)
359b47b79d8SRamesh Shanmugasundaram 		mxm_err(ctx, "wbits ret(%d): idx 0x%02x\n", ret, idx);
360b47b79d8SRamesh Shanmugasundaram 
361b47b79d8SRamesh Shanmugasundaram 	return ret;
362b47b79d8SRamesh Shanmugasundaram }
363b47b79d8SRamesh Shanmugasundaram 
max2175_write_bit(struct max2175 * ctx,u8 idx,u8 bit,u8 newval)364b47b79d8SRamesh Shanmugasundaram static int max2175_write_bit(struct max2175 *ctx, u8 idx, u8 bit, u8 newval)
365b47b79d8SRamesh Shanmugasundaram {
366b47b79d8SRamesh Shanmugasundaram 	return max2175_write_bits(ctx, idx, bit, bit, newval);
367b47b79d8SRamesh Shanmugasundaram }
368b47b79d8SRamesh Shanmugasundaram 
369b47b79d8SRamesh Shanmugasundaram /* Checks expected pattern every msec until timeout */
max2175_poll_timeout(struct max2175 * ctx,u8 idx,u8 msb,u8 lsb,u8 exp_bitval,u32 timeout_us)370b47b79d8SRamesh Shanmugasundaram static int max2175_poll_timeout(struct max2175 *ctx, u8 idx, u8 msb, u8 lsb,
371b47b79d8SRamesh Shanmugasundaram 				u8 exp_bitval, u32 timeout_us)
372b47b79d8SRamesh Shanmugasundaram {
373b47b79d8SRamesh Shanmugasundaram 	unsigned int val;
374b47b79d8SRamesh Shanmugasundaram 
375b47b79d8SRamesh Shanmugasundaram 	return regmap_read_poll_timeout(ctx->regmap, idx, val,
376b47b79d8SRamesh Shanmugasundaram 			(max2175_get_bitval(val, msb, lsb) == exp_bitval),
377b47b79d8SRamesh Shanmugasundaram 			1000, timeout_us);
378b47b79d8SRamesh Shanmugasundaram }
379b47b79d8SRamesh Shanmugasundaram 
max2175_poll_csm_ready(struct max2175 * ctx)380b47b79d8SRamesh Shanmugasundaram static int max2175_poll_csm_ready(struct max2175 *ctx)
381b47b79d8SRamesh Shanmugasundaram {
382b47b79d8SRamesh Shanmugasundaram 	int ret;
383b47b79d8SRamesh Shanmugasundaram 
384b47b79d8SRamesh Shanmugasundaram 	ret = max2175_poll_timeout(ctx, 69, 1, 1, 0, 50000);
385b47b79d8SRamesh Shanmugasundaram 	if (ret)
386b47b79d8SRamesh Shanmugasundaram 		mxm_err(ctx, "csm not ready\n");
387b47b79d8SRamesh Shanmugasundaram 
388b47b79d8SRamesh Shanmugasundaram 	return ret;
389b47b79d8SRamesh Shanmugasundaram }
390b47b79d8SRamesh Shanmugasundaram 
391b47b79d8SRamesh Shanmugasundaram #define MAX2175_IS_BAND_AM(ctx)		\
392b47b79d8SRamesh Shanmugasundaram 	(max2175_read_bits(ctx, 5, 1, 0) == MAX2175_BAND_AM)
393b47b79d8SRamesh Shanmugasundaram 
394b47b79d8SRamesh Shanmugasundaram #define MAX2175_IS_BAND_VHF(ctx)	\
395b47b79d8SRamesh Shanmugasundaram 	(max2175_read_bits(ctx, 5, 1, 0) == MAX2175_BAND_VHF)
396b47b79d8SRamesh Shanmugasundaram 
397b47b79d8SRamesh Shanmugasundaram #define MAX2175_IS_FM_MODE(ctx)		\
398b47b79d8SRamesh Shanmugasundaram 	(max2175_read_bits(ctx, 12, 5, 4) == 0)
399b47b79d8SRamesh Shanmugasundaram 
400b47b79d8SRamesh Shanmugasundaram #define MAX2175_IS_FMHD_MODE(ctx)	\
401b47b79d8SRamesh Shanmugasundaram 	(max2175_read_bits(ctx, 12, 5, 4) == 1)
402b47b79d8SRamesh Shanmugasundaram 
403b47b79d8SRamesh Shanmugasundaram #define MAX2175_IS_DAB_MODE(ctx)	\
404b47b79d8SRamesh Shanmugasundaram 	(max2175_read_bits(ctx, 12, 5, 4) == 2)
405b47b79d8SRamesh Shanmugasundaram 
max2175_band_from_freq(u32 freq)406b47b79d8SRamesh Shanmugasundaram static int max2175_band_from_freq(u32 freq)
407b47b79d8SRamesh Shanmugasundaram {
408b47b79d8SRamesh Shanmugasundaram 	if (freq >= 144000 && freq <= 26100000)
409b47b79d8SRamesh Shanmugasundaram 		return MAX2175_BAND_AM;
410b47b79d8SRamesh Shanmugasundaram 	else if (freq >= 65000000 && freq <= 108000000)
411b47b79d8SRamesh Shanmugasundaram 		return MAX2175_BAND_FM;
412b47b79d8SRamesh Shanmugasundaram 
413b47b79d8SRamesh Shanmugasundaram 	return MAX2175_BAND_VHF;
414b47b79d8SRamesh Shanmugasundaram }
415b47b79d8SRamesh Shanmugasundaram 
max2175_i2s_enable(struct max2175 * ctx,bool enable)416b47b79d8SRamesh Shanmugasundaram static void max2175_i2s_enable(struct max2175 *ctx, bool enable)
417b47b79d8SRamesh Shanmugasundaram {
418b47b79d8SRamesh Shanmugasundaram 	if (enable)
419b47b79d8SRamesh Shanmugasundaram 		/* Stuff bits are zeroed */
420b47b79d8SRamesh Shanmugasundaram 		max2175_write_bits(ctx, 104, 3, 0, 2);
421b47b79d8SRamesh Shanmugasundaram 	else
422b47b79d8SRamesh Shanmugasundaram 		/* Keep SCK alive */
423b47b79d8SRamesh Shanmugasundaram 		max2175_write_bits(ctx, 104, 3, 0, 9);
424b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "i2s %sabled\n", enable ? "en" : "dis");
425b47b79d8SRamesh Shanmugasundaram }
426b47b79d8SRamesh Shanmugasundaram 
max2175_set_filter_coeffs(struct max2175 * ctx,u8 m_sel,u8 bank,const u16 * coeffs)427b47b79d8SRamesh Shanmugasundaram static void max2175_set_filter_coeffs(struct max2175 *ctx, u8 m_sel,
428b47b79d8SRamesh Shanmugasundaram 				      u8 bank, const u16 *coeffs)
429b47b79d8SRamesh Shanmugasundaram {
430b47b79d8SRamesh Shanmugasundaram 	unsigned int i;
431b47b79d8SRamesh Shanmugasundaram 	u8 coeff_addr, upper_address = 24;
432b47b79d8SRamesh Shanmugasundaram 
433b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "set_filter_coeffs: m_sel %d bank %d\n", m_sel, bank);
434b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 114, 5, 4, m_sel);
435b47b79d8SRamesh Shanmugasundaram 
436b47b79d8SRamesh Shanmugasundaram 	if (m_sel == 2)
437b47b79d8SRamesh Shanmugasundaram 		upper_address = 12;
438b47b79d8SRamesh Shanmugasundaram 
439b47b79d8SRamesh Shanmugasundaram 	for (i = 0; i < upper_address; i++) {
440b47b79d8SRamesh Shanmugasundaram 		coeff_addr = i + bank * 24;
441b47b79d8SRamesh Shanmugasundaram 		max2175_write(ctx, 115, coeffs[i] >> 8);
442b47b79d8SRamesh Shanmugasundaram 		max2175_write(ctx, 116, coeffs[i]);
443b47b79d8SRamesh Shanmugasundaram 		max2175_write(ctx, 117, coeff_addr | 1 << 7);
444b47b79d8SRamesh Shanmugasundaram 	}
445b47b79d8SRamesh Shanmugasundaram 	max2175_write_bit(ctx, 117, 7, 0);
446b47b79d8SRamesh Shanmugasundaram }
447b47b79d8SRamesh Shanmugasundaram 
max2175_load_fmeu_1p2(struct max2175 * ctx)448b47b79d8SRamesh Shanmugasundaram static void max2175_load_fmeu_1p2(struct max2175 *ctx)
449b47b79d8SRamesh Shanmugasundaram {
450b47b79d8SRamesh Shanmugasundaram 	unsigned int i;
451b47b79d8SRamesh Shanmugasundaram 
452b47b79d8SRamesh Shanmugasundaram 	for (i = 0; i < ARRAY_SIZE(fmeu1p2_map); i++)
453b47b79d8SRamesh Shanmugasundaram 		max2175_write(ctx, fmeu1p2_map[i].idx, fmeu1p2_map[i].val);
454b47b79d8SRamesh Shanmugasundaram 
455b47b79d8SRamesh Shanmugasundaram 	ctx->decim_ratio = 36;
456b47b79d8SRamesh Shanmugasundaram 
457b47b79d8SRamesh Shanmugasundaram 	/* Load the Channel Filter Coefficients into channel filter bank #2 */
458b47b79d8SRamesh Shanmugasundaram 	max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 0, ch_coeff_fmeu);
459b47b79d8SRamesh Shanmugasundaram 	max2175_set_filter_coeffs(ctx, MAX2175_EQ_MSEL, 0,
460b47b79d8SRamesh Shanmugasundaram 				  eq_coeff_fmeu1_ra02_m6db);
461b47b79d8SRamesh Shanmugasundaram }
462b47b79d8SRamesh Shanmugasundaram 
max2175_load_dab_1p2(struct max2175 * ctx)463b47b79d8SRamesh Shanmugasundaram static void max2175_load_dab_1p2(struct max2175 *ctx)
464b47b79d8SRamesh Shanmugasundaram {
465b47b79d8SRamesh Shanmugasundaram 	unsigned int i;
466b47b79d8SRamesh Shanmugasundaram 
467b47b79d8SRamesh Shanmugasundaram 	for (i = 0; i < ARRAY_SIZE(dab12_map); i++)
468b47b79d8SRamesh Shanmugasundaram 		max2175_write(ctx, dab12_map[i].idx, dab12_map[i].val);
469b47b79d8SRamesh Shanmugasundaram 
470b47b79d8SRamesh Shanmugasundaram 	ctx->decim_ratio = 1;
471b47b79d8SRamesh Shanmugasundaram 
472b47b79d8SRamesh Shanmugasundaram 	/* Load the Channel Filter Coefficients into channel filter bank #2 */
473b47b79d8SRamesh Shanmugasundaram 	max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 2, ch_coeff_dab1);
474b47b79d8SRamesh Shanmugasundaram }
475b47b79d8SRamesh Shanmugasundaram 
max2175_load_fmna_1p0(struct max2175 * ctx)476b47b79d8SRamesh Shanmugasundaram static void max2175_load_fmna_1p0(struct max2175 *ctx)
477b47b79d8SRamesh Shanmugasundaram {
478b47b79d8SRamesh Shanmugasundaram 	unsigned int i;
479b47b79d8SRamesh Shanmugasundaram 
480b47b79d8SRamesh Shanmugasundaram 	for (i = 0; i < ARRAY_SIZE(fmna1p0_map); i++)
481b47b79d8SRamesh Shanmugasundaram 		max2175_write(ctx, fmna1p0_map[i].idx, fmna1p0_map[i].val);
482b47b79d8SRamesh Shanmugasundaram }
483b47b79d8SRamesh Shanmugasundaram 
max2175_load_fmna_2p0(struct max2175 * ctx)484b47b79d8SRamesh Shanmugasundaram static void max2175_load_fmna_2p0(struct max2175 *ctx)
485b47b79d8SRamesh Shanmugasundaram {
486b47b79d8SRamesh Shanmugasundaram 	unsigned int i;
487b47b79d8SRamesh Shanmugasundaram 
488b47b79d8SRamesh Shanmugasundaram 	for (i = 0; i < ARRAY_SIZE(fmna2p0_map); i++)
489b47b79d8SRamesh Shanmugasundaram 		max2175_write(ctx, fmna2p0_map[i].idx, fmna2p0_map[i].val);
490b47b79d8SRamesh Shanmugasundaram }
491b47b79d8SRamesh Shanmugasundaram 
max2175_set_bbfilter(struct max2175 * ctx)492b47b79d8SRamesh Shanmugasundaram static void max2175_set_bbfilter(struct max2175 *ctx)
493b47b79d8SRamesh Shanmugasundaram {
494b47b79d8SRamesh Shanmugasundaram 	if (MAX2175_IS_BAND_AM(ctx)) {
495b47b79d8SRamesh Shanmugasundaram 		max2175_write_bits(ctx, 12, 3, 0, ctx->rom_bbf_bw_am);
496b47b79d8SRamesh Shanmugasundaram 		mxm_dbg(ctx, "set_bbfilter AM: rom %d\n", ctx->rom_bbf_bw_am);
497b47b79d8SRamesh Shanmugasundaram 	} else if (MAX2175_IS_DAB_MODE(ctx)) {
498b47b79d8SRamesh Shanmugasundaram 		max2175_write_bits(ctx, 12, 3, 0, ctx->rom_bbf_bw_dab);
499b47b79d8SRamesh Shanmugasundaram 		mxm_dbg(ctx, "set_bbfilter DAB: rom %d\n", ctx->rom_bbf_bw_dab);
500b47b79d8SRamesh Shanmugasundaram 	} else {
501b47b79d8SRamesh Shanmugasundaram 		max2175_write_bits(ctx, 12, 3, 0, ctx->rom_bbf_bw_fm);
502b47b79d8SRamesh Shanmugasundaram 		mxm_dbg(ctx, "set_bbfilter FM: rom %d\n", ctx->rom_bbf_bw_fm);
503b47b79d8SRamesh Shanmugasundaram 	}
504b47b79d8SRamesh Shanmugasundaram }
505b47b79d8SRamesh Shanmugasundaram 
max2175_set_csm_mode(struct max2175 * ctx,enum max2175_csm_mode new_mode)5069b1b0cb0SDan Carpenter static int max2175_set_csm_mode(struct max2175 *ctx,
507b47b79d8SRamesh Shanmugasundaram 			  enum max2175_csm_mode new_mode)
508b47b79d8SRamesh Shanmugasundaram {
509b47b79d8SRamesh Shanmugasundaram 	int ret = max2175_poll_csm_ready(ctx);
510b47b79d8SRamesh Shanmugasundaram 
511b47b79d8SRamesh Shanmugasundaram 	if (ret)
512b47b79d8SRamesh Shanmugasundaram 		return ret;
513b47b79d8SRamesh Shanmugasundaram 
514b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 0, 2, 0, new_mode);
515b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "set csm new mode %d\n", new_mode);
516b47b79d8SRamesh Shanmugasundaram 
517b47b79d8SRamesh Shanmugasundaram 	/* Wait for a fixed settle down time depending on new mode */
518b47b79d8SRamesh Shanmugasundaram 	switch (new_mode) {
519b47b79d8SRamesh Shanmugasundaram 	case MAX2175_PRESET_TUNE:
520b47b79d8SRamesh Shanmugasundaram 		usleep_range(51100, 51500);	/* 51.1ms */
521b47b79d8SRamesh Shanmugasundaram 		break;
522b47b79d8SRamesh Shanmugasundaram 	/*
523b47b79d8SRamesh Shanmugasundaram 	 * Other mode switches need different sleep values depending on band &
524b47b79d8SRamesh Shanmugasundaram 	 * mode
525b47b79d8SRamesh Shanmugasundaram 	 */
526b47b79d8SRamesh Shanmugasundaram 	default:
527b47b79d8SRamesh Shanmugasundaram 		break;
528b47b79d8SRamesh Shanmugasundaram 	}
529b47b79d8SRamesh Shanmugasundaram 
530b47b79d8SRamesh Shanmugasundaram 	return max2175_poll_csm_ready(ctx);
531b47b79d8SRamesh Shanmugasundaram }
532b47b79d8SRamesh Shanmugasundaram 
max2175_csm_action(struct max2175 * ctx,enum max2175_csm_mode action)533b47b79d8SRamesh Shanmugasundaram static int max2175_csm_action(struct max2175 *ctx,
534b47b79d8SRamesh Shanmugasundaram 			      enum max2175_csm_mode action)
535b47b79d8SRamesh Shanmugasundaram {
536b47b79d8SRamesh Shanmugasundaram 	int ret;
537b47b79d8SRamesh Shanmugasundaram 
538b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "csm_action: %d\n", action);
539b47b79d8SRamesh Shanmugasundaram 
540b47b79d8SRamesh Shanmugasundaram 	/* Other actions can be added in future when needed */
541b47b79d8SRamesh Shanmugasundaram 	ret = max2175_set_csm_mode(ctx, MAX2175_LOAD_TO_BUFFER);
542b47b79d8SRamesh Shanmugasundaram 	if (ret)
543b47b79d8SRamesh Shanmugasundaram 		return ret;
544b47b79d8SRamesh Shanmugasundaram 
545b47b79d8SRamesh Shanmugasundaram 	return max2175_set_csm_mode(ctx, MAX2175_PRESET_TUNE);
546b47b79d8SRamesh Shanmugasundaram }
547b47b79d8SRamesh Shanmugasundaram 
max2175_set_lo_freq(struct max2175 * ctx,u32 lo_freq)548b47b79d8SRamesh Shanmugasundaram static int max2175_set_lo_freq(struct max2175 *ctx, u32 lo_freq)
549b47b79d8SRamesh Shanmugasundaram {
550b47b79d8SRamesh Shanmugasundaram 	u8 lo_mult, loband_bits = 0, vcodiv_bits = 0;
551b47b79d8SRamesh Shanmugasundaram 	u32 int_desired, frac_desired;
552b47b79d8SRamesh Shanmugasundaram 	enum max2175_band band;
553b47b79d8SRamesh Shanmugasundaram 	int ret;
554b47b79d8SRamesh Shanmugasundaram 
555b47b79d8SRamesh Shanmugasundaram 	band = max2175_read_bits(ctx, 5, 1, 0);
556b47b79d8SRamesh Shanmugasundaram 	switch (band) {
557b47b79d8SRamesh Shanmugasundaram 	case MAX2175_BAND_AM:
558b47b79d8SRamesh Shanmugasundaram 		lo_mult = 16;
559b47b79d8SRamesh Shanmugasundaram 		break;
560b47b79d8SRamesh Shanmugasundaram 	case MAX2175_BAND_FM:
561b47b79d8SRamesh Shanmugasundaram 		if (lo_freq <= 74700000) {
562b47b79d8SRamesh Shanmugasundaram 			lo_mult = 16;
563b47b79d8SRamesh Shanmugasundaram 		} else if (lo_freq > 74700000 && lo_freq <= 110000000) {
564b47b79d8SRamesh Shanmugasundaram 			loband_bits = 1;
565b47b79d8SRamesh Shanmugasundaram 			lo_mult = 8;
566b47b79d8SRamesh Shanmugasundaram 		} else {
567b47b79d8SRamesh Shanmugasundaram 			loband_bits = 1;
568b47b79d8SRamesh Shanmugasundaram 			vcodiv_bits = 3;
569b47b79d8SRamesh Shanmugasundaram 			lo_mult = 8;
570b47b79d8SRamesh Shanmugasundaram 		}
571b47b79d8SRamesh Shanmugasundaram 		break;
572b47b79d8SRamesh Shanmugasundaram 	case MAX2175_BAND_VHF:
573b47b79d8SRamesh Shanmugasundaram 		if (lo_freq <= 210000000)
574b47b79d8SRamesh Shanmugasundaram 			vcodiv_bits = 2;
575b47b79d8SRamesh Shanmugasundaram 		else
576b47b79d8SRamesh Shanmugasundaram 			vcodiv_bits = 1;
577b47b79d8SRamesh Shanmugasundaram 
578b47b79d8SRamesh Shanmugasundaram 		loband_bits = 2;
579b47b79d8SRamesh Shanmugasundaram 		lo_mult = 4;
580b47b79d8SRamesh Shanmugasundaram 		break;
581b47b79d8SRamesh Shanmugasundaram 	default:
582b47b79d8SRamesh Shanmugasundaram 		loband_bits = 3;
583b47b79d8SRamesh Shanmugasundaram 		vcodiv_bits = 2;
584b47b79d8SRamesh Shanmugasundaram 		lo_mult = 2;
585b47b79d8SRamesh Shanmugasundaram 		break;
586b47b79d8SRamesh Shanmugasundaram 	}
587b47b79d8SRamesh Shanmugasundaram 
588b47b79d8SRamesh Shanmugasundaram 	if (band == MAX2175_BAND_L)
589b47b79d8SRamesh Shanmugasundaram 		lo_freq /= lo_mult;
590b47b79d8SRamesh Shanmugasundaram 	else
591b47b79d8SRamesh Shanmugasundaram 		lo_freq *= lo_mult;
592b47b79d8SRamesh Shanmugasundaram 
593b47b79d8SRamesh Shanmugasundaram 	int_desired = lo_freq / ctx->xtal_freq;
594672c29b9SGeert Uytterhoeven 	frac_desired = div64_ul((u64)(lo_freq % ctx->xtal_freq) << 20,
595b47b79d8SRamesh Shanmugasundaram 				ctx->xtal_freq);
596b47b79d8SRamesh Shanmugasundaram 
597b47b79d8SRamesh Shanmugasundaram 	/* Check CSM is not busy */
598b47b79d8SRamesh Shanmugasundaram 	ret = max2175_poll_csm_ready(ctx);
599b47b79d8SRamesh Shanmugasundaram 	if (ret)
600b47b79d8SRamesh Shanmugasundaram 		return ret;
601b47b79d8SRamesh Shanmugasundaram 
602b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "lo_mult %u int %u  frac %u\n",
603b47b79d8SRamesh Shanmugasundaram 		lo_mult, int_desired, frac_desired);
604b47b79d8SRamesh Shanmugasundaram 
605b47b79d8SRamesh Shanmugasundaram 	/* Write the calculated values to the appropriate registers */
606b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 1, int_desired);
607b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 2, 3, 0, (frac_desired >> 16) & 0xf);
608b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 3, frac_desired >> 8);
609b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 4, frac_desired);
610b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 5, 3, 2, loband_bits);
611b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 6, 7, 6, vcodiv_bits);
612b47b79d8SRamesh Shanmugasundaram 
613b47b79d8SRamesh Shanmugasundaram 	return ret;
614b47b79d8SRamesh Shanmugasundaram }
615b47b79d8SRamesh Shanmugasundaram 
616b47b79d8SRamesh Shanmugasundaram /*
617b47b79d8SRamesh Shanmugasundaram  * Helper similar to DIV_ROUND_CLOSEST but an inline function that accepts s64
618b47b79d8SRamesh Shanmugasundaram  * dividend and s32 divisor
619b47b79d8SRamesh Shanmugasundaram  */
max2175_round_closest(s64 dividend,s32 divisor)620b47b79d8SRamesh Shanmugasundaram static inline s64 max2175_round_closest(s64 dividend, s32 divisor)
621b47b79d8SRamesh Shanmugasundaram {
622b47b79d8SRamesh Shanmugasundaram 	if ((dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0))
623b47b79d8SRamesh Shanmugasundaram 		return div_s64(dividend + divisor / 2, divisor);
624b47b79d8SRamesh Shanmugasundaram 
625b47b79d8SRamesh Shanmugasundaram 	return div_s64(dividend - divisor / 2, divisor);
626b47b79d8SRamesh Shanmugasundaram }
627b47b79d8SRamesh Shanmugasundaram 
max2175_set_nco_freq(struct max2175 * ctx,s32 nco_freq)628b47b79d8SRamesh Shanmugasundaram static int max2175_set_nco_freq(struct max2175 *ctx, s32 nco_freq)
629b47b79d8SRamesh Shanmugasundaram {
630b47b79d8SRamesh Shanmugasundaram 	s32 clock_rate = ctx->xtal_freq / ctx->decim_ratio;
631b47b79d8SRamesh Shanmugasundaram 	u32 nco_reg, abs_nco_freq = abs(nco_freq);
632b47b79d8SRamesh Shanmugasundaram 	s64 nco_val_desired;
633b47b79d8SRamesh Shanmugasundaram 	int ret;
634b47b79d8SRamesh Shanmugasundaram 
635b47b79d8SRamesh Shanmugasundaram 	if (abs_nco_freq < clock_rate / 2) {
636b47b79d8SRamesh Shanmugasundaram 		nco_val_desired = 2 * nco_freq;
637b47b79d8SRamesh Shanmugasundaram 	} else {
638a2603d17SGustavo A. R. Silva 		nco_val_desired = 2LL * (clock_rate - abs_nco_freq);
639b47b79d8SRamesh Shanmugasundaram 		if (nco_freq < 0)
640b47b79d8SRamesh Shanmugasundaram 			nco_val_desired = -nco_val_desired;
641b47b79d8SRamesh Shanmugasundaram 	}
642b47b79d8SRamesh Shanmugasundaram 
643b47b79d8SRamesh Shanmugasundaram 	nco_reg = max2175_round_closest(nco_val_desired << 20, clock_rate);
644b47b79d8SRamesh Shanmugasundaram 
645b47b79d8SRamesh Shanmugasundaram 	if (nco_freq < 0)
646b47b79d8SRamesh Shanmugasundaram 		nco_reg += 0x200000;
647b47b79d8SRamesh Shanmugasundaram 
648b47b79d8SRamesh Shanmugasundaram 	/* Check CSM is not busy */
649b47b79d8SRamesh Shanmugasundaram 	ret = max2175_poll_csm_ready(ctx);
650b47b79d8SRamesh Shanmugasundaram 	if (ret)
651b47b79d8SRamesh Shanmugasundaram 		return ret;
652b47b79d8SRamesh Shanmugasundaram 
653b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "freq %d desired %lld reg %u\n",
654b47b79d8SRamesh Shanmugasundaram 		nco_freq, nco_val_desired, nco_reg);
655b47b79d8SRamesh Shanmugasundaram 
656b47b79d8SRamesh Shanmugasundaram 	/* Write the calculated values to the appropriate registers */
657b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 7, 4, 0, (nco_reg >> 16) & 0x1f);
658b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 8, nco_reg >> 8);
659b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 9, nco_reg);
660b47b79d8SRamesh Shanmugasundaram 
661b47b79d8SRamesh Shanmugasundaram 	return ret;
662b47b79d8SRamesh Shanmugasundaram }
663b47b79d8SRamesh Shanmugasundaram 
max2175_set_rf_freq_non_am_bands(struct max2175 * ctx,u64 freq,u32 lo_pos)664b47b79d8SRamesh Shanmugasundaram static int max2175_set_rf_freq_non_am_bands(struct max2175 *ctx, u64 freq,
665b47b79d8SRamesh Shanmugasundaram 					    u32 lo_pos)
666b47b79d8SRamesh Shanmugasundaram {
667b47b79d8SRamesh Shanmugasundaram 	s64 adj_freq, low_if_freq;
668b47b79d8SRamesh Shanmugasundaram 	int ret;
669b47b79d8SRamesh Shanmugasundaram 
670b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "rf_freq: non AM bands\n");
671b47b79d8SRamesh Shanmugasundaram 
672b47b79d8SRamesh Shanmugasundaram 	if (MAX2175_IS_FM_MODE(ctx))
673b47b79d8SRamesh Shanmugasundaram 		low_if_freq = 128000;
674b47b79d8SRamesh Shanmugasundaram 	else if (MAX2175_IS_FMHD_MODE(ctx))
675b47b79d8SRamesh Shanmugasundaram 		low_if_freq = 228000;
676b47b79d8SRamesh Shanmugasundaram 	else
677b47b79d8SRamesh Shanmugasundaram 		return max2175_set_lo_freq(ctx, freq);
678b47b79d8SRamesh Shanmugasundaram 
679b47b79d8SRamesh Shanmugasundaram 	if (MAX2175_IS_BAND_VHF(ctx) == (lo_pos == MAX2175_LO_ABOVE_DESIRED))
680b47b79d8SRamesh Shanmugasundaram 		adj_freq = freq + low_if_freq;
681b47b79d8SRamesh Shanmugasundaram 	else
682b47b79d8SRamesh Shanmugasundaram 		adj_freq = freq - low_if_freq;
683b47b79d8SRamesh Shanmugasundaram 
684b47b79d8SRamesh Shanmugasundaram 	ret = max2175_set_lo_freq(ctx, adj_freq);
685b47b79d8SRamesh Shanmugasundaram 	if (ret)
686b47b79d8SRamesh Shanmugasundaram 		return ret;
687b47b79d8SRamesh Shanmugasundaram 
688b47b79d8SRamesh Shanmugasundaram 	return max2175_set_nco_freq(ctx, -low_if_freq);
689b47b79d8SRamesh Shanmugasundaram }
690b47b79d8SRamesh Shanmugasundaram 
max2175_set_rf_freq(struct max2175 * ctx,u64 freq,u32 lo_pos)691b47b79d8SRamesh Shanmugasundaram static int max2175_set_rf_freq(struct max2175 *ctx, u64 freq, u32 lo_pos)
692b47b79d8SRamesh Shanmugasundaram {
693b47b79d8SRamesh Shanmugasundaram 	int ret;
694b47b79d8SRamesh Shanmugasundaram 
695b47b79d8SRamesh Shanmugasundaram 	if (MAX2175_IS_BAND_AM(ctx))
696b47b79d8SRamesh Shanmugasundaram 		ret = max2175_set_nco_freq(ctx, freq);
697b47b79d8SRamesh Shanmugasundaram 	else
698b47b79d8SRamesh Shanmugasundaram 		ret = max2175_set_rf_freq_non_am_bands(ctx, freq, lo_pos);
699b47b79d8SRamesh Shanmugasundaram 
700b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "set_rf_freq: ret %d freq %llu\n", ret, freq);
701b47b79d8SRamesh Shanmugasundaram 
702b47b79d8SRamesh Shanmugasundaram 	return ret;
703b47b79d8SRamesh Shanmugasundaram }
704b47b79d8SRamesh Shanmugasundaram 
max2175_tune_rf_freq(struct max2175 * ctx,u64 freq,u32 hsls)705b47b79d8SRamesh Shanmugasundaram static int max2175_tune_rf_freq(struct max2175 *ctx, u64 freq, u32 hsls)
706b47b79d8SRamesh Shanmugasundaram {
707b47b79d8SRamesh Shanmugasundaram 	int ret;
708b47b79d8SRamesh Shanmugasundaram 
709b47b79d8SRamesh Shanmugasundaram 	ret = max2175_set_rf_freq(ctx, freq, hsls);
710b47b79d8SRamesh Shanmugasundaram 	if (ret)
711b47b79d8SRamesh Shanmugasundaram 		return ret;
712b47b79d8SRamesh Shanmugasundaram 
713b47b79d8SRamesh Shanmugasundaram 	ret = max2175_csm_action(ctx, MAX2175_BUFFER_PLUS_PRESET_TUNE);
714b47b79d8SRamesh Shanmugasundaram 	if (ret)
715b47b79d8SRamesh Shanmugasundaram 		return ret;
716b47b79d8SRamesh Shanmugasundaram 
717b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "tune_rf_freq: old %u new %llu\n", ctx->freq, freq);
718b47b79d8SRamesh Shanmugasundaram 	ctx->freq = freq;
719b47b79d8SRamesh Shanmugasundaram 
720b47b79d8SRamesh Shanmugasundaram 	return ret;
721b47b79d8SRamesh Shanmugasundaram }
722b47b79d8SRamesh Shanmugasundaram 
max2175_set_hsls(struct max2175 * ctx,u32 lo_pos)723b47b79d8SRamesh Shanmugasundaram static void max2175_set_hsls(struct max2175 *ctx, u32 lo_pos)
724b47b79d8SRamesh Shanmugasundaram {
725b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "set_hsls: lo_pos %u\n", lo_pos);
726b47b79d8SRamesh Shanmugasundaram 
727b47b79d8SRamesh Shanmugasundaram 	if ((lo_pos == MAX2175_LO_BELOW_DESIRED) == MAX2175_IS_BAND_VHF(ctx))
728b47b79d8SRamesh Shanmugasundaram 		max2175_write_bit(ctx, 5, 4, 1);
729b47b79d8SRamesh Shanmugasundaram 	else
730b47b79d8SRamesh Shanmugasundaram 		max2175_write_bit(ctx, 5, 4, 0);
731b47b79d8SRamesh Shanmugasundaram }
732b47b79d8SRamesh Shanmugasundaram 
max2175_set_eu_rx_mode(struct max2175 * ctx,u32 rx_mode)733b47b79d8SRamesh Shanmugasundaram static void max2175_set_eu_rx_mode(struct max2175 *ctx, u32 rx_mode)
734b47b79d8SRamesh Shanmugasundaram {
735b47b79d8SRamesh Shanmugasundaram 	switch (rx_mode) {
736b47b79d8SRamesh Shanmugasundaram 	case MAX2175_EU_FM_1_2:
737b47b79d8SRamesh Shanmugasundaram 		max2175_load_fmeu_1p2(ctx);
738b47b79d8SRamesh Shanmugasundaram 		break;
739b47b79d8SRamesh Shanmugasundaram 
740b47b79d8SRamesh Shanmugasundaram 	case MAX2175_DAB_1_2:
741b47b79d8SRamesh Shanmugasundaram 		max2175_load_dab_1p2(ctx);
742b47b79d8SRamesh Shanmugasundaram 		break;
743b47b79d8SRamesh Shanmugasundaram 	}
744b47b79d8SRamesh Shanmugasundaram 	/* Master is the default setting */
745b47b79d8SRamesh Shanmugasundaram 	if (!ctx->master)
746b47b79d8SRamesh Shanmugasundaram 		max2175_write_bit(ctx, 30, 7, 1);
747b47b79d8SRamesh Shanmugasundaram }
748b47b79d8SRamesh Shanmugasundaram 
max2175_set_na_rx_mode(struct max2175 * ctx,u32 rx_mode)749b47b79d8SRamesh Shanmugasundaram static void max2175_set_na_rx_mode(struct max2175 *ctx, u32 rx_mode)
750b47b79d8SRamesh Shanmugasundaram {
751b47b79d8SRamesh Shanmugasundaram 	switch (rx_mode) {
752b47b79d8SRamesh Shanmugasundaram 	case MAX2175_NA_FM_1_0:
753b47b79d8SRamesh Shanmugasundaram 		max2175_load_fmna_1p0(ctx);
754b47b79d8SRamesh Shanmugasundaram 		break;
755b47b79d8SRamesh Shanmugasundaram 	case MAX2175_NA_FM_2_0:
756b47b79d8SRamesh Shanmugasundaram 		max2175_load_fmna_2p0(ctx);
757b47b79d8SRamesh Shanmugasundaram 		break;
758b47b79d8SRamesh Shanmugasundaram 	}
759b47b79d8SRamesh Shanmugasundaram 	/* Master is the default setting */
760b47b79d8SRamesh Shanmugasundaram 	if (!ctx->master)
761b47b79d8SRamesh Shanmugasundaram 		max2175_write_bit(ctx, 30, 7, 1);
762b47b79d8SRamesh Shanmugasundaram 
763b47b79d8SRamesh Shanmugasundaram 	ctx->decim_ratio = 27;
764b47b79d8SRamesh Shanmugasundaram 
765b47b79d8SRamesh Shanmugasundaram 	/* Load the Channel Filter Coefficients into channel filter bank #2 */
766b47b79d8SRamesh Shanmugasundaram 	max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 0, ch_coeff_fmna);
767b47b79d8SRamesh Shanmugasundaram 	max2175_set_filter_coeffs(ctx, MAX2175_EQ_MSEL, 0,
768b47b79d8SRamesh Shanmugasundaram 				  eq_coeff_fmna1_ra02_m6db);
769b47b79d8SRamesh Shanmugasundaram }
770b47b79d8SRamesh Shanmugasundaram 
max2175_set_rx_mode(struct max2175 * ctx,u32 rx_mode)771b47b79d8SRamesh Shanmugasundaram static int max2175_set_rx_mode(struct max2175 *ctx, u32 rx_mode)
772b47b79d8SRamesh Shanmugasundaram {
773b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "set_rx_mode: %u am_hiz %u\n", rx_mode, ctx->am_hiz);
774b47b79d8SRamesh Shanmugasundaram 	if (ctx->xtal_freq == MAX2175_EU_XTAL_FREQ)
775b47b79d8SRamesh Shanmugasundaram 		max2175_set_eu_rx_mode(ctx, rx_mode);
776b47b79d8SRamesh Shanmugasundaram 	else
777b47b79d8SRamesh Shanmugasundaram 		max2175_set_na_rx_mode(ctx, rx_mode);
778b47b79d8SRamesh Shanmugasundaram 
779b47b79d8SRamesh Shanmugasundaram 	if (ctx->am_hiz) {
780b47b79d8SRamesh Shanmugasundaram 		mxm_dbg(ctx, "setting AM HiZ related config\n");
781b47b79d8SRamesh Shanmugasundaram 		max2175_write_bit(ctx, 50, 5, 1);
782b47b79d8SRamesh Shanmugasundaram 		max2175_write_bit(ctx, 90, 7, 1);
783b47b79d8SRamesh Shanmugasundaram 		max2175_write_bits(ctx, 73, 1, 0, 2);
784b47b79d8SRamesh Shanmugasundaram 		max2175_write_bits(ctx, 80, 5, 0, 33);
785b47b79d8SRamesh Shanmugasundaram 	}
786b47b79d8SRamesh Shanmugasundaram 
787b47b79d8SRamesh Shanmugasundaram 	/* Load BB filter trim values saved in ROM */
788b47b79d8SRamesh Shanmugasundaram 	max2175_set_bbfilter(ctx);
789b47b79d8SRamesh Shanmugasundaram 
790b47b79d8SRamesh Shanmugasundaram 	/* Set HSLS */
791b47b79d8SRamesh Shanmugasundaram 	max2175_set_hsls(ctx, ctx->hsls->cur.val);
792b47b79d8SRamesh Shanmugasundaram 
793b47b79d8SRamesh Shanmugasundaram 	/* Use i2s enable settings */
794b47b79d8SRamesh Shanmugasundaram 	max2175_i2s_enable(ctx, ctx->i2s_en->cur.val);
795b47b79d8SRamesh Shanmugasundaram 
796b47b79d8SRamesh Shanmugasundaram 	ctx->mode_resolved = true;
797b47b79d8SRamesh Shanmugasundaram 
798b47b79d8SRamesh Shanmugasundaram 	return 0;
799b47b79d8SRamesh Shanmugasundaram }
800b47b79d8SRamesh Shanmugasundaram 
max2175_rx_mode_from_freq(struct max2175 * ctx,u32 freq,u32 * mode)801b47b79d8SRamesh Shanmugasundaram static int max2175_rx_mode_from_freq(struct max2175 *ctx, u32 freq, u32 *mode)
802b47b79d8SRamesh Shanmugasundaram {
803b47b79d8SRamesh Shanmugasundaram 	unsigned int i;
804b47b79d8SRamesh Shanmugasundaram 	int band = max2175_band_from_freq(freq);
805b47b79d8SRamesh Shanmugasundaram 
806b47b79d8SRamesh Shanmugasundaram 	/* Pick the first match always */
807b47b79d8SRamesh Shanmugasundaram 	for (i = 0; i <= ctx->rx_mode->maximum; i++) {
808b47b79d8SRamesh Shanmugasundaram 		if (ctx->rx_modes[i].band == band) {
809b47b79d8SRamesh Shanmugasundaram 			*mode = i;
810b47b79d8SRamesh Shanmugasundaram 			mxm_dbg(ctx, "rx_mode_from_freq: freq %u mode %d\n",
811b47b79d8SRamesh Shanmugasundaram 				freq, *mode);
812b47b79d8SRamesh Shanmugasundaram 			return 0;
813b47b79d8SRamesh Shanmugasundaram 		}
814b47b79d8SRamesh Shanmugasundaram 	}
815b47b79d8SRamesh Shanmugasundaram 
816b47b79d8SRamesh Shanmugasundaram 	return -EINVAL;
817b47b79d8SRamesh Shanmugasundaram }
818b47b79d8SRamesh Shanmugasundaram 
max2175_freq_rx_mode_valid(struct max2175 * ctx,u32 mode,u32 freq)819b47b79d8SRamesh Shanmugasundaram static bool max2175_freq_rx_mode_valid(struct max2175 *ctx,
820b47b79d8SRamesh Shanmugasundaram 					 u32 mode, u32 freq)
821b47b79d8SRamesh Shanmugasundaram {
822b47b79d8SRamesh Shanmugasundaram 	int band = max2175_band_from_freq(freq);
823b47b79d8SRamesh Shanmugasundaram 
824b47b79d8SRamesh Shanmugasundaram 	return (ctx->rx_modes[mode].band == band);
825b47b79d8SRamesh Shanmugasundaram }
826b47b79d8SRamesh Shanmugasundaram 
max2175_load_adc_presets(struct max2175 * ctx)827b47b79d8SRamesh Shanmugasundaram static void max2175_load_adc_presets(struct max2175 *ctx)
828b47b79d8SRamesh Shanmugasundaram {
829b47b79d8SRamesh Shanmugasundaram 	unsigned int i, j;
830b47b79d8SRamesh Shanmugasundaram 
831b47b79d8SRamesh Shanmugasundaram 	for (i = 0; i < ARRAY_SIZE(adc_presets); i++)
832b47b79d8SRamesh Shanmugasundaram 		for (j = 0; j < ARRAY_SIZE(adc_presets[0]); j++)
833b47b79d8SRamesh Shanmugasundaram 			max2175_write(ctx, 146 + j + i * 55, adc_presets[i][j]);
834b47b79d8SRamesh Shanmugasundaram }
835b47b79d8SRamesh Shanmugasundaram 
max2175_init_power_manager(struct max2175 * ctx)836b47b79d8SRamesh Shanmugasundaram static int max2175_init_power_manager(struct max2175 *ctx)
837b47b79d8SRamesh Shanmugasundaram {
838b47b79d8SRamesh Shanmugasundaram 	int ret;
839b47b79d8SRamesh Shanmugasundaram 
840b47b79d8SRamesh Shanmugasundaram 	/* Execute on-chip power-up/calibration */
841b47b79d8SRamesh Shanmugasundaram 	max2175_write_bit(ctx, 99, 2, 0);
842b47b79d8SRamesh Shanmugasundaram 	usleep_range(1000, 1500);
843b47b79d8SRamesh Shanmugasundaram 	max2175_write_bit(ctx, 99, 2, 1);
844b47b79d8SRamesh Shanmugasundaram 
845b47b79d8SRamesh Shanmugasundaram 	/* Wait for the power manager to finish. */
846b47b79d8SRamesh Shanmugasundaram 	ret = max2175_poll_timeout(ctx, 69, 7, 7, 1, 50000);
847b47b79d8SRamesh Shanmugasundaram 	if (ret)
848b47b79d8SRamesh Shanmugasundaram 		mxm_err(ctx, "init pm failed\n");
849b47b79d8SRamesh Shanmugasundaram 
850b47b79d8SRamesh Shanmugasundaram 	return ret;
851b47b79d8SRamesh Shanmugasundaram }
852b47b79d8SRamesh Shanmugasundaram 
max2175_recalibrate_adc(struct max2175 * ctx)853b47b79d8SRamesh Shanmugasundaram static int max2175_recalibrate_adc(struct max2175 *ctx)
854b47b79d8SRamesh Shanmugasundaram {
855b47b79d8SRamesh Shanmugasundaram 	int ret;
856b47b79d8SRamesh Shanmugasundaram 
857b47b79d8SRamesh Shanmugasundaram 	/* ADC Re-calibration */
858b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 150, 0xff);
859b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 205, 0xff);
860b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 147, 0x20);
861b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 147, 0x00);
862b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 202, 0x20);
863b47b79d8SRamesh Shanmugasundaram 	max2175_write(ctx, 202, 0x00);
864b47b79d8SRamesh Shanmugasundaram 
865b47b79d8SRamesh Shanmugasundaram 	ret = max2175_poll_timeout(ctx, 69, 4, 3, 3, 50000);
866b47b79d8SRamesh Shanmugasundaram 	if (ret)
867b47b79d8SRamesh Shanmugasundaram 		mxm_err(ctx, "adc recalibration failed\n");
868b47b79d8SRamesh Shanmugasundaram 
869b47b79d8SRamesh Shanmugasundaram 	return ret;
870b47b79d8SRamesh Shanmugasundaram }
871b47b79d8SRamesh Shanmugasundaram 
max2175_read_rom(struct max2175 * ctx,u8 row)872b47b79d8SRamesh Shanmugasundaram static u8 max2175_read_rom(struct max2175 *ctx, u8 row)
873b47b79d8SRamesh Shanmugasundaram {
874b47b79d8SRamesh Shanmugasundaram 	u8 data = 0;
875b47b79d8SRamesh Shanmugasundaram 
876b47b79d8SRamesh Shanmugasundaram 	max2175_write_bit(ctx, 56, 4, 0);
877b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 56, 3, 0, row);
878b47b79d8SRamesh Shanmugasundaram 
879b47b79d8SRamesh Shanmugasundaram 	usleep_range(2000, 2500);
880b47b79d8SRamesh Shanmugasundaram 	max2175_read(ctx, 58, &data);
881b47b79d8SRamesh Shanmugasundaram 
882b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 56, 3, 0, 0);
883b47b79d8SRamesh Shanmugasundaram 
884b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "read_rom: row %d data 0x%02x\n", row, data);
885b47b79d8SRamesh Shanmugasundaram 
886b47b79d8SRamesh Shanmugasundaram 	return data;
887b47b79d8SRamesh Shanmugasundaram }
888b47b79d8SRamesh Shanmugasundaram 
max2175_load_from_rom(struct max2175 * ctx)889b47b79d8SRamesh Shanmugasundaram static void max2175_load_from_rom(struct max2175 *ctx)
890b47b79d8SRamesh Shanmugasundaram {
891b47b79d8SRamesh Shanmugasundaram 	u8 data = 0;
892b47b79d8SRamesh Shanmugasundaram 
893b47b79d8SRamesh Shanmugasundaram 	data = max2175_read_rom(ctx, 0);
894b47b79d8SRamesh Shanmugasundaram 	ctx->rom_bbf_bw_am = data & 0x0f;
895b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 81, 3, 0, data >> 4);
896b47b79d8SRamesh Shanmugasundaram 
897b47b79d8SRamesh Shanmugasundaram 	data = max2175_read_rom(ctx, 1);
898b47b79d8SRamesh Shanmugasundaram 	ctx->rom_bbf_bw_fm = data & 0x0f;
899b47b79d8SRamesh Shanmugasundaram 	ctx->rom_bbf_bw_dab = data >> 4;
900b47b79d8SRamesh Shanmugasundaram 
901b47b79d8SRamesh Shanmugasundaram 	data = max2175_read_rom(ctx, 2);
902b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 82, 4, 0, data & 0x1f);
903b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 82, 7, 5, data >> 5);
904b47b79d8SRamesh Shanmugasundaram 
905b47b79d8SRamesh Shanmugasundaram 	data = max2175_read_rom(ctx, 3);
906b47b79d8SRamesh Shanmugasundaram 	if (ctx->am_hiz) {
907b47b79d8SRamesh Shanmugasundaram 		data &= 0x0f;
908b47b79d8SRamesh Shanmugasundaram 		data |= (max2175_read_rom(ctx, 7) & 0x40) >> 2;
909b47b79d8SRamesh Shanmugasundaram 		if (!data)
910b47b79d8SRamesh Shanmugasundaram 			data |= 2;
911b47b79d8SRamesh Shanmugasundaram 	} else {
912b47b79d8SRamesh Shanmugasundaram 		data = (data & 0xf0) >> 4;
913b47b79d8SRamesh Shanmugasundaram 		data |= (max2175_read_rom(ctx, 7) & 0x80) >> 3;
914b47b79d8SRamesh Shanmugasundaram 		if (!data)
915b47b79d8SRamesh Shanmugasundaram 			data |= 30;
916b47b79d8SRamesh Shanmugasundaram 	}
917b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 80, 5, 0, data + 31);
918b47b79d8SRamesh Shanmugasundaram 
919b47b79d8SRamesh Shanmugasundaram 	data = max2175_read_rom(ctx, 6);
920b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 81, 7, 6, data >> 6);
921b47b79d8SRamesh Shanmugasundaram }
922b47b79d8SRamesh Shanmugasundaram 
max2175_load_full_fm_eu_1p0(struct max2175 * ctx)923b47b79d8SRamesh Shanmugasundaram static void max2175_load_full_fm_eu_1p0(struct max2175 *ctx)
924b47b79d8SRamesh Shanmugasundaram {
925b47b79d8SRamesh Shanmugasundaram 	unsigned int i;
926b47b79d8SRamesh Shanmugasundaram 
927b47b79d8SRamesh Shanmugasundaram 	for (i = 0; i < ARRAY_SIZE(full_fm_eu_1p0); i++)
928b47b79d8SRamesh Shanmugasundaram 		max2175_write(ctx, i + 1, full_fm_eu_1p0[i]);
929b47b79d8SRamesh Shanmugasundaram 
930b47b79d8SRamesh Shanmugasundaram 	usleep_range(5000, 5500);
931b47b79d8SRamesh Shanmugasundaram 	ctx->decim_ratio = 36;
932b47b79d8SRamesh Shanmugasundaram }
933b47b79d8SRamesh Shanmugasundaram 
max2175_load_full_fm_na_1p0(struct max2175 * ctx)934b47b79d8SRamesh Shanmugasundaram static void max2175_load_full_fm_na_1p0(struct max2175 *ctx)
935b47b79d8SRamesh Shanmugasundaram {
936b47b79d8SRamesh Shanmugasundaram 	unsigned int i;
937b47b79d8SRamesh Shanmugasundaram 
938b47b79d8SRamesh Shanmugasundaram 	for (i = 0; i < ARRAY_SIZE(full_fm_na_1p0); i++)
939b47b79d8SRamesh Shanmugasundaram 		max2175_write(ctx, i + 1, full_fm_na_1p0[i]);
940b47b79d8SRamesh Shanmugasundaram 
941b47b79d8SRamesh Shanmugasundaram 	usleep_range(5000, 5500);
942b47b79d8SRamesh Shanmugasundaram 	ctx->decim_ratio = 27;
943b47b79d8SRamesh Shanmugasundaram }
944b47b79d8SRamesh Shanmugasundaram 
max2175_core_init(struct max2175 * ctx,u32 refout_bits)945b47b79d8SRamesh Shanmugasundaram static int max2175_core_init(struct max2175 *ctx, u32 refout_bits)
946b47b79d8SRamesh Shanmugasundaram {
947b47b79d8SRamesh Shanmugasundaram 	int ret;
948b47b79d8SRamesh Shanmugasundaram 
949b47b79d8SRamesh Shanmugasundaram 	/* MAX2175 uses 36.864MHz clock for EU & 40.154MHz for NA region */
950b47b79d8SRamesh Shanmugasundaram 	if (ctx->xtal_freq == MAX2175_EU_XTAL_FREQ)
951b47b79d8SRamesh Shanmugasundaram 		max2175_load_full_fm_eu_1p0(ctx);
952b47b79d8SRamesh Shanmugasundaram 	else
953b47b79d8SRamesh Shanmugasundaram 		max2175_load_full_fm_na_1p0(ctx);
954b47b79d8SRamesh Shanmugasundaram 
955b47b79d8SRamesh Shanmugasundaram 	/* The default settings assume master */
956b47b79d8SRamesh Shanmugasundaram 	if (!ctx->master)
957b47b79d8SRamesh Shanmugasundaram 		max2175_write_bit(ctx, 30, 7, 1);
958b47b79d8SRamesh Shanmugasundaram 
959b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "refout_bits %u\n", refout_bits);
960b47b79d8SRamesh Shanmugasundaram 
961b47b79d8SRamesh Shanmugasundaram 	/* Set REFOUT */
962b47b79d8SRamesh Shanmugasundaram 	max2175_write_bits(ctx, 56, 7, 5, refout_bits);
963b47b79d8SRamesh Shanmugasundaram 
964b47b79d8SRamesh Shanmugasundaram 	/* ADC Reset */
965b47b79d8SRamesh Shanmugasundaram 	max2175_write_bit(ctx, 99, 1, 0);
966b47b79d8SRamesh Shanmugasundaram 	usleep_range(1000, 1500);
967b47b79d8SRamesh Shanmugasundaram 	max2175_write_bit(ctx, 99, 1, 1);
968b47b79d8SRamesh Shanmugasundaram 
969b47b79d8SRamesh Shanmugasundaram 	/* Load ADC preset values */
970b47b79d8SRamesh Shanmugasundaram 	max2175_load_adc_presets(ctx);
971b47b79d8SRamesh Shanmugasundaram 
972b47b79d8SRamesh Shanmugasundaram 	/* Initialize the power management state machine */
973b47b79d8SRamesh Shanmugasundaram 	ret = max2175_init_power_manager(ctx);
974b47b79d8SRamesh Shanmugasundaram 	if (ret)
975b47b79d8SRamesh Shanmugasundaram 		return ret;
976b47b79d8SRamesh Shanmugasundaram 
977b47b79d8SRamesh Shanmugasundaram 	/* Recalibrate ADC */
978b47b79d8SRamesh Shanmugasundaram 	ret = max2175_recalibrate_adc(ctx);
979b47b79d8SRamesh Shanmugasundaram 	if (ret)
980b47b79d8SRamesh Shanmugasundaram 		return ret;
981b47b79d8SRamesh Shanmugasundaram 
982b47b79d8SRamesh Shanmugasundaram 	/* Load ROM values to appropriate registers */
983b47b79d8SRamesh Shanmugasundaram 	max2175_load_from_rom(ctx);
984b47b79d8SRamesh Shanmugasundaram 
985b47b79d8SRamesh Shanmugasundaram 	if (ctx->xtal_freq == MAX2175_EU_XTAL_FREQ) {
986b47b79d8SRamesh Shanmugasundaram 		/* Load FIR coefficients into bank 0 */
987b47b79d8SRamesh Shanmugasundaram 		max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 0,
988b47b79d8SRamesh Shanmugasundaram 					  ch_coeff_fmeu);
989b47b79d8SRamesh Shanmugasundaram 		max2175_set_filter_coeffs(ctx, MAX2175_EQ_MSEL, 0,
990b47b79d8SRamesh Shanmugasundaram 					  eq_coeff_fmeu1_ra02_m6db);
991b47b79d8SRamesh Shanmugasundaram 	} else {
992b47b79d8SRamesh Shanmugasundaram 		/* Load FIR coefficients into bank 0 */
993b47b79d8SRamesh Shanmugasundaram 		max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 0,
994b47b79d8SRamesh Shanmugasundaram 					  ch_coeff_fmna);
995b47b79d8SRamesh Shanmugasundaram 		max2175_set_filter_coeffs(ctx, MAX2175_EQ_MSEL, 0,
996b47b79d8SRamesh Shanmugasundaram 					  eq_coeff_fmna1_ra02_m6db);
997b47b79d8SRamesh Shanmugasundaram 	}
998b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "core initialized\n");
999b47b79d8SRamesh Shanmugasundaram 
1000b47b79d8SRamesh Shanmugasundaram 	return 0;
1001b47b79d8SRamesh Shanmugasundaram }
1002b47b79d8SRamesh Shanmugasundaram 
max2175_s_ctrl_rx_mode(struct max2175 * ctx,u32 rx_mode)1003b47b79d8SRamesh Shanmugasundaram static void max2175_s_ctrl_rx_mode(struct max2175 *ctx, u32 rx_mode)
1004b47b79d8SRamesh Shanmugasundaram {
1005b47b79d8SRamesh Shanmugasundaram 	/* Load mode. Range check already done */
1006b47b79d8SRamesh Shanmugasundaram 	max2175_set_rx_mode(ctx, rx_mode);
1007b47b79d8SRamesh Shanmugasundaram 
1008b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "s_ctrl_rx_mode: %u curr freq %u\n", rx_mode, ctx->freq);
1009b47b79d8SRamesh Shanmugasundaram 
1010b47b79d8SRamesh Shanmugasundaram 	/* Check if current freq valid for mode & update */
1011b47b79d8SRamesh Shanmugasundaram 	if (max2175_freq_rx_mode_valid(ctx, rx_mode, ctx->freq))
1012b47b79d8SRamesh Shanmugasundaram 		max2175_tune_rf_freq(ctx, ctx->freq, ctx->hsls->cur.val);
1013b47b79d8SRamesh Shanmugasundaram 	else
1014b47b79d8SRamesh Shanmugasundaram 		/* Use default freq of mode if current freq is not valid */
1015b47b79d8SRamesh Shanmugasundaram 		max2175_tune_rf_freq(ctx, ctx->rx_modes[rx_mode].freq,
1016b47b79d8SRamesh Shanmugasundaram 				     ctx->hsls->cur.val);
1017b47b79d8SRamesh Shanmugasundaram }
1018b47b79d8SRamesh Shanmugasundaram 
max2175_s_ctrl(struct v4l2_ctrl * ctrl)1019b47b79d8SRamesh Shanmugasundaram static int max2175_s_ctrl(struct v4l2_ctrl *ctrl)
1020b47b79d8SRamesh Shanmugasundaram {
1021b47b79d8SRamesh Shanmugasundaram 	struct max2175 *ctx = max2175_from_ctrl_hdl(ctrl->handler);
1022b47b79d8SRamesh Shanmugasundaram 
1023b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "s_ctrl: id 0x%x, val %u\n", ctrl->id, ctrl->val);
1024b47b79d8SRamesh Shanmugasundaram 	switch (ctrl->id) {
1025b47b79d8SRamesh Shanmugasundaram 	case V4L2_CID_MAX2175_I2S_ENABLE:
1026b47b79d8SRamesh Shanmugasundaram 		max2175_i2s_enable(ctx, ctrl->val);
1027b47b79d8SRamesh Shanmugasundaram 		break;
1028b47b79d8SRamesh Shanmugasundaram 	case V4L2_CID_MAX2175_HSLS:
1029b47b79d8SRamesh Shanmugasundaram 		max2175_set_hsls(ctx, ctrl->val);
1030b47b79d8SRamesh Shanmugasundaram 		break;
1031b47b79d8SRamesh Shanmugasundaram 	case V4L2_CID_MAX2175_RX_MODE:
1032b47b79d8SRamesh Shanmugasundaram 		max2175_s_ctrl_rx_mode(ctx, ctrl->val);
1033b47b79d8SRamesh Shanmugasundaram 		break;
1034b47b79d8SRamesh Shanmugasundaram 	}
1035b47b79d8SRamesh Shanmugasundaram 
1036b47b79d8SRamesh Shanmugasundaram 	return 0;
1037b47b79d8SRamesh Shanmugasundaram }
1038b47b79d8SRamesh Shanmugasundaram 
max2175_get_lna_gain(struct max2175 * ctx)1039b47b79d8SRamesh Shanmugasundaram static u32 max2175_get_lna_gain(struct max2175 *ctx)
1040b47b79d8SRamesh Shanmugasundaram {
1041b47b79d8SRamesh Shanmugasundaram 	enum max2175_band band = max2175_read_bits(ctx, 5, 1, 0);
1042b47b79d8SRamesh Shanmugasundaram 
1043b47b79d8SRamesh Shanmugasundaram 	switch (band) {
1044b47b79d8SRamesh Shanmugasundaram 	case MAX2175_BAND_AM:
1045b47b79d8SRamesh Shanmugasundaram 		return max2175_read_bits(ctx, 51, 3, 0);
1046b47b79d8SRamesh Shanmugasundaram 	case MAX2175_BAND_FM:
1047b47b79d8SRamesh Shanmugasundaram 		return max2175_read_bits(ctx, 50, 3, 0);
1048b47b79d8SRamesh Shanmugasundaram 	case MAX2175_BAND_VHF:
1049b47b79d8SRamesh Shanmugasundaram 		return max2175_read_bits(ctx, 52, 5, 0);
1050b47b79d8SRamesh Shanmugasundaram 	default:
1051b47b79d8SRamesh Shanmugasundaram 		return 0;
1052b47b79d8SRamesh Shanmugasundaram 	}
1053b47b79d8SRamesh Shanmugasundaram }
1054b47b79d8SRamesh Shanmugasundaram 
max2175_g_volatile_ctrl(struct v4l2_ctrl * ctrl)1055b47b79d8SRamesh Shanmugasundaram static int max2175_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
1056b47b79d8SRamesh Shanmugasundaram {
1057b47b79d8SRamesh Shanmugasundaram 	struct max2175 *ctx = max2175_from_ctrl_hdl(ctrl->handler);
1058b47b79d8SRamesh Shanmugasundaram 
1059b47b79d8SRamesh Shanmugasundaram 	switch (ctrl->id) {
1060b47b79d8SRamesh Shanmugasundaram 	case V4L2_CID_RF_TUNER_LNA_GAIN:
1061b47b79d8SRamesh Shanmugasundaram 		ctrl->val = max2175_get_lna_gain(ctx);
1062b47b79d8SRamesh Shanmugasundaram 		break;
1063b47b79d8SRamesh Shanmugasundaram 	case V4L2_CID_RF_TUNER_IF_GAIN:
1064b47b79d8SRamesh Shanmugasundaram 		ctrl->val = max2175_read_bits(ctx, 49, 4, 0);
1065b47b79d8SRamesh Shanmugasundaram 		break;
1066b47b79d8SRamesh Shanmugasundaram 	case V4L2_CID_RF_TUNER_PLL_LOCK:
1067b47b79d8SRamesh Shanmugasundaram 		ctrl->val = (max2175_read_bits(ctx, 60, 7, 6) == 3);
1068b47b79d8SRamesh Shanmugasundaram 		break;
1069b47b79d8SRamesh Shanmugasundaram 	}
1070b47b79d8SRamesh Shanmugasundaram 
1071b47b79d8SRamesh Shanmugasundaram 	return 0;
1072b47b79d8SRamesh Shanmugasundaram };
1073b47b79d8SRamesh Shanmugasundaram 
max2175_set_freq_and_mode(struct max2175 * ctx,u32 freq)1074b47b79d8SRamesh Shanmugasundaram static int max2175_set_freq_and_mode(struct max2175 *ctx, u32 freq)
1075b47b79d8SRamesh Shanmugasundaram {
1076b47b79d8SRamesh Shanmugasundaram 	u32 rx_mode;
1077b47b79d8SRamesh Shanmugasundaram 	int ret;
1078b47b79d8SRamesh Shanmugasundaram 
1079b47b79d8SRamesh Shanmugasundaram 	/* Get band from frequency */
1080b47b79d8SRamesh Shanmugasundaram 	ret = max2175_rx_mode_from_freq(ctx, freq, &rx_mode);
1081b47b79d8SRamesh Shanmugasundaram 	if (ret)
1082b47b79d8SRamesh Shanmugasundaram 		return ret;
1083b47b79d8SRamesh Shanmugasundaram 
1084b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "set_freq_and_mode: freq %u rx_mode %d\n", freq, rx_mode);
1085b47b79d8SRamesh Shanmugasundaram 
1086b47b79d8SRamesh Shanmugasundaram 	/* Load mode */
1087b47b79d8SRamesh Shanmugasundaram 	max2175_set_rx_mode(ctx, rx_mode);
1088b47b79d8SRamesh Shanmugasundaram 	ctx->rx_mode->cur.val = rx_mode;
1089b47b79d8SRamesh Shanmugasundaram 
1090b47b79d8SRamesh Shanmugasundaram 	/* Tune to the new freq given */
1091b47b79d8SRamesh Shanmugasundaram 	return max2175_tune_rf_freq(ctx, freq, ctx->hsls->cur.val);
1092b47b79d8SRamesh Shanmugasundaram }
1093b47b79d8SRamesh Shanmugasundaram 
max2175_s_frequency(struct v4l2_subdev * sd,const struct v4l2_frequency * vf)1094b47b79d8SRamesh Shanmugasundaram static int max2175_s_frequency(struct v4l2_subdev *sd,
1095b47b79d8SRamesh Shanmugasundaram 			       const struct v4l2_frequency *vf)
1096b47b79d8SRamesh Shanmugasundaram {
1097b47b79d8SRamesh Shanmugasundaram 	struct max2175 *ctx = max2175_from_sd(sd);
1098b47b79d8SRamesh Shanmugasundaram 	u32 freq;
1099b47b79d8SRamesh Shanmugasundaram 	int ret = 0;
1100b47b79d8SRamesh Shanmugasundaram 
1101b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "s_freq: new %u curr %u, mode_resolved %d\n",
1102b47b79d8SRamesh Shanmugasundaram 		vf->frequency, ctx->freq, ctx->mode_resolved);
1103b47b79d8SRamesh Shanmugasundaram 
1104b47b79d8SRamesh Shanmugasundaram 	if (vf->tuner != 0)
1105b47b79d8SRamesh Shanmugasundaram 		return -EINVAL;
1106b47b79d8SRamesh Shanmugasundaram 
1107b47b79d8SRamesh Shanmugasundaram 	freq = clamp(vf->frequency, ctx->bands_rf->rangelow,
1108b47b79d8SRamesh Shanmugasundaram 		     ctx->bands_rf->rangehigh);
1109b47b79d8SRamesh Shanmugasundaram 
1110b47b79d8SRamesh Shanmugasundaram 	/* Check new freq valid for rx_mode if already resolved */
1111b47b79d8SRamesh Shanmugasundaram 	if (ctx->mode_resolved &&
1112b47b79d8SRamesh Shanmugasundaram 	    max2175_freq_rx_mode_valid(ctx, ctx->rx_mode->cur.val, freq))
1113b47b79d8SRamesh Shanmugasundaram 		ret = max2175_tune_rf_freq(ctx, freq, ctx->hsls->cur.val);
1114b47b79d8SRamesh Shanmugasundaram 	else
1115b47b79d8SRamesh Shanmugasundaram 		/* Find default rx_mode for freq and tune to it */
1116b47b79d8SRamesh Shanmugasundaram 		ret = max2175_set_freq_and_mode(ctx, freq);
1117b47b79d8SRamesh Shanmugasundaram 
1118b47b79d8SRamesh Shanmugasundaram 	mxm_dbg(ctx, "s_freq: ret %d curr %u mode_resolved %d mode %u\n",
1119b47b79d8SRamesh Shanmugasundaram 		ret, ctx->freq, ctx->mode_resolved, ctx->rx_mode->cur.val);
1120b47b79d8SRamesh Shanmugasundaram 
1121b47b79d8SRamesh Shanmugasundaram 	return ret;
1122b47b79d8SRamesh Shanmugasundaram }
1123b47b79d8SRamesh Shanmugasundaram 
max2175_g_frequency(struct v4l2_subdev * sd,struct v4l2_frequency * vf)1124b47b79d8SRamesh Shanmugasundaram static int max2175_g_frequency(struct v4l2_subdev *sd,
1125b47b79d8SRamesh Shanmugasundaram 			       struct v4l2_frequency *vf)
1126b47b79d8SRamesh Shanmugasundaram {
1127b47b79d8SRamesh Shanmugasundaram 	struct max2175 *ctx = max2175_from_sd(sd);
1128b47b79d8SRamesh Shanmugasundaram 
1129b47b79d8SRamesh Shanmugasundaram 	if (vf->tuner != 0)
1130b47b79d8SRamesh Shanmugasundaram 		return -EINVAL;
1131b47b79d8SRamesh Shanmugasundaram 
1132b47b79d8SRamesh Shanmugasundaram 	/* RF freq */
1133b47b79d8SRamesh Shanmugasundaram 	vf->type = V4L2_TUNER_RF;
1134b47b79d8SRamesh Shanmugasundaram 	vf->frequency = ctx->freq;
1135b47b79d8SRamesh Shanmugasundaram 
1136f0b8bbd3Szuoqilin 	return 0;
1137b47b79d8SRamesh Shanmugasundaram }
1138b47b79d8SRamesh Shanmugasundaram 
max2175_enum_freq_bands(struct v4l2_subdev * sd,struct v4l2_frequency_band * band)1139b47b79d8SRamesh Shanmugasundaram static int max2175_enum_freq_bands(struct v4l2_subdev *sd,
1140b47b79d8SRamesh Shanmugasundaram 			    struct v4l2_frequency_band *band)
1141b47b79d8SRamesh Shanmugasundaram {
1142b47b79d8SRamesh Shanmugasundaram 	struct max2175 *ctx = max2175_from_sd(sd);
1143b47b79d8SRamesh Shanmugasundaram 
1144b47b79d8SRamesh Shanmugasundaram 	if (band->tuner != 0 || band->index != 0)
1145b47b79d8SRamesh Shanmugasundaram 		return -EINVAL;
1146b47b79d8SRamesh Shanmugasundaram 
1147b47b79d8SRamesh Shanmugasundaram 	*band = *ctx->bands_rf;
1148b47b79d8SRamesh Shanmugasundaram 
1149b47b79d8SRamesh Shanmugasundaram 	return 0;
1150b47b79d8SRamesh Shanmugasundaram }
1151b47b79d8SRamesh Shanmugasundaram 
max2175_g_tuner(struct v4l2_subdev * sd,struct v4l2_tuner * vt)1152b47b79d8SRamesh Shanmugasundaram static int max2175_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
1153b47b79d8SRamesh Shanmugasundaram {
1154b47b79d8SRamesh Shanmugasundaram 	struct max2175 *ctx = max2175_from_sd(sd);
1155b47b79d8SRamesh Shanmugasundaram 
1156b47b79d8SRamesh Shanmugasundaram 	if (vt->index > 0)
1157b47b79d8SRamesh Shanmugasundaram 		return -EINVAL;
1158b47b79d8SRamesh Shanmugasundaram 
1159c0decac1SMauro Carvalho Chehab 	strscpy(vt->name, "RF", sizeof(vt->name));
1160b47b79d8SRamesh Shanmugasundaram 	vt->type = V4L2_TUNER_RF;
1161b47b79d8SRamesh Shanmugasundaram 	vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
1162b47b79d8SRamesh Shanmugasundaram 	vt->rangelow = ctx->bands_rf->rangelow;
1163b47b79d8SRamesh Shanmugasundaram 	vt->rangehigh = ctx->bands_rf->rangehigh;
1164b47b79d8SRamesh Shanmugasundaram 
1165b47b79d8SRamesh Shanmugasundaram 	return 0;
1166b47b79d8SRamesh Shanmugasundaram }
1167b47b79d8SRamesh Shanmugasundaram 
max2175_s_tuner(struct v4l2_subdev * sd,const struct v4l2_tuner * vt)1168b47b79d8SRamesh Shanmugasundaram static int max2175_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt)
1169b47b79d8SRamesh Shanmugasundaram {
1170b47b79d8SRamesh Shanmugasundaram 	/* Check tuner index is valid */
1171b47b79d8SRamesh Shanmugasundaram 	if (vt->index > 0)
1172b47b79d8SRamesh Shanmugasundaram 		return -EINVAL;
1173b47b79d8SRamesh Shanmugasundaram 
1174b47b79d8SRamesh Shanmugasundaram 	return 0;
1175b47b79d8SRamesh Shanmugasundaram }
1176b47b79d8SRamesh Shanmugasundaram 
1177b47b79d8SRamesh Shanmugasundaram static const struct v4l2_subdev_tuner_ops max2175_tuner_ops = {
1178b47b79d8SRamesh Shanmugasundaram 	.s_frequency = max2175_s_frequency,
1179b47b79d8SRamesh Shanmugasundaram 	.g_frequency = max2175_g_frequency,
1180b47b79d8SRamesh Shanmugasundaram 	.enum_freq_bands = max2175_enum_freq_bands,
1181b47b79d8SRamesh Shanmugasundaram 	.g_tuner = max2175_g_tuner,
1182b47b79d8SRamesh Shanmugasundaram 	.s_tuner = max2175_s_tuner,
1183b47b79d8SRamesh Shanmugasundaram };
1184b47b79d8SRamesh Shanmugasundaram 
1185b47b79d8SRamesh Shanmugasundaram static const struct v4l2_subdev_ops max2175_ops = {
1186b47b79d8SRamesh Shanmugasundaram 	.tuner = &max2175_tuner_ops,
1187b47b79d8SRamesh Shanmugasundaram };
1188b47b79d8SRamesh Shanmugasundaram 
1189b47b79d8SRamesh Shanmugasundaram static const struct v4l2_ctrl_ops max2175_ctrl_ops = {
1190b47b79d8SRamesh Shanmugasundaram 	.s_ctrl = max2175_s_ctrl,
1191b47b79d8SRamesh Shanmugasundaram 	.g_volatile_ctrl = max2175_g_volatile_ctrl,
1192b47b79d8SRamesh Shanmugasundaram };
1193b47b79d8SRamesh Shanmugasundaram 
1194b47b79d8SRamesh Shanmugasundaram /*
1195b47b79d8SRamesh Shanmugasundaram  * I2S output enable/disable configuration. This is a private control.
1196b3634386SMauro Carvalho Chehab  * Refer to Documentation/userspace-api/media/drivers/max2175.rst for more details.
1197b47b79d8SRamesh Shanmugasundaram  */
1198b47b79d8SRamesh Shanmugasundaram static const struct v4l2_ctrl_config max2175_i2s_en = {
1199b47b79d8SRamesh Shanmugasundaram 	.ops = &max2175_ctrl_ops,
1200b47b79d8SRamesh Shanmugasundaram 	.id = V4L2_CID_MAX2175_I2S_ENABLE,
1201b47b79d8SRamesh Shanmugasundaram 	.name = "I2S Enable",
1202b47b79d8SRamesh Shanmugasundaram 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1203b47b79d8SRamesh Shanmugasundaram 	.min = 0,
1204b47b79d8SRamesh Shanmugasundaram 	.max = 1,
1205b47b79d8SRamesh Shanmugasundaram 	.step = 1,
1206b47b79d8SRamesh Shanmugasundaram 	.def = 1,
1207b47b79d8SRamesh Shanmugasundaram 	.is_private = 1,
1208b47b79d8SRamesh Shanmugasundaram };
1209b47b79d8SRamesh Shanmugasundaram 
1210b47b79d8SRamesh Shanmugasundaram /*
1211b47b79d8SRamesh Shanmugasundaram  * HSLS value control LO freq adjacent location configuration.
1212b3634386SMauro Carvalho Chehab  * Refer to Documentation/userspace-api/media/drivers/max2175.rst for more details.
1213b47b79d8SRamesh Shanmugasundaram  */
1214b47b79d8SRamesh Shanmugasundaram static const struct v4l2_ctrl_config max2175_hsls = {
1215b47b79d8SRamesh Shanmugasundaram 	.ops = &max2175_ctrl_ops,
1216b47b79d8SRamesh Shanmugasundaram 	.id = V4L2_CID_MAX2175_HSLS,
1217b47b79d8SRamesh Shanmugasundaram 	.name = "HSLS Above/Below Desired",
1218b47b79d8SRamesh Shanmugasundaram 	.type = V4L2_CTRL_TYPE_BOOLEAN,
1219b47b79d8SRamesh Shanmugasundaram 	.min = 0,
1220b47b79d8SRamesh Shanmugasundaram 	.max = 1,
1221b47b79d8SRamesh Shanmugasundaram 	.step = 1,
1222b47b79d8SRamesh Shanmugasundaram 	.def = 1,
1223b47b79d8SRamesh Shanmugasundaram };
1224b47b79d8SRamesh Shanmugasundaram 
1225b47b79d8SRamesh Shanmugasundaram /*
1226b47b79d8SRamesh Shanmugasundaram  * Rx modes below are a set of preset configurations that decides the tuner's
1227b47b79d8SRamesh Shanmugasundaram  * sck and sample rate of transmission. They are separate for EU & NA regions.
1228b3634386SMauro Carvalho Chehab  * Refer to Documentation/userspace-api/media/drivers/max2175.rst for more details.
1229b47b79d8SRamesh Shanmugasundaram  */
1230b47b79d8SRamesh Shanmugasundaram static const char * const max2175_ctrl_eu_rx_modes[] = {
1231b47b79d8SRamesh Shanmugasundaram 	[MAX2175_EU_FM_1_2]	= "EU FM 1.2",
1232b47b79d8SRamesh Shanmugasundaram 	[MAX2175_DAB_1_2]	= "DAB 1.2",
1233b47b79d8SRamesh Shanmugasundaram };
1234b47b79d8SRamesh Shanmugasundaram 
1235b47b79d8SRamesh Shanmugasundaram static const char * const max2175_ctrl_na_rx_modes[] = {
1236b47b79d8SRamesh Shanmugasundaram 	[MAX2175_NA_FM_1_0]	= "NA FM 1.0",
1237b47b79d8SRamesh Shanmugasundaram 	[MAX2175_NA_FM_2_0]	= "NA FM 2.0",
1238b47b79d8SRamesh Shanmugasundaram };
1239b47b79d8SRamesh Shanmugasundaram 
1240b47b79d8SRamesh Shanmugasundaram static const struct v4l2_ctrl_config max2175_eu_rx_mode = {
1241b47b79d8SRamesh Shanmugasundaram 	.ops = &max2175_ctrl_ops,
1242b47b79d8SRamesh Shanmugasundaram 	.id = V4L2_CID_MAX2175_RX_MODE,
1243b47b79d8SRamesh Shanmugasundaram 	.name = "RX Mode",
1244b47b79d8SRamesh Shanmugasundaram 	.type = V4L2_CTRL_TYPE_MENU,
1245b47b79d8SRamesh Shanmugasundaram 	.max = ARRAY_SIZE(max2175_ctrl_eu_rx_modes) - 1,
1246b47b79d8SRamesh Shanmugasundaram 	.def = 0,
1247b47b79d8SRamesh Shanmugasundaram 	.qmenu = max2175_ctrl_eu_rx_modes,
1248b47b79d8SRamesh Shanmugasundaram };
1249b47b79d8SRamesh Shanmugasundaram 
1250b47b79d8SRamesh Shanmugasundaram static const struct v4l2_ctrl_config max2175_na_rx_mode = {
1251b47b79d8SRamesh Shanmugasundaram 	.ops = &max2175_ctrl_ops,
1252b47b79d8SRamesh Shanmugasundaram 	.id = V4L2_CID_MAX2175_RX_MODE,
1253b47b79d8SRamesh Shanmugasundaram 	.name = "RX Mode",
1254b47b79d8SRamesh Shanmugasundaram 	.type = V4L2_CTRL_TYPE_MENU,
1255b47b79d8SRamesh Shanmugasundaram 	.max = ARRAY_SIZE(max2175_ctrl_na_rx_modes) - 1,
1256b47b79d8SRamesh Shanmugasundaram 	.def = 0,
1257b47b79d8SRamesh Shanmugasundaram 	.qmenu = max2175_ctrl_na_rx_modes,
1258b47b79d8SRamesh Shanmugasundaram };
1259b47b79d8SRamesh Shanmugasundaram 
max2175_refout_load_to_bits(struct i2c_client * client,u32 load,u32 * bits)1260b47b79d8SRamesh Shanmugasundaram static int max2175_refout_load_to_bits(struct i2c_client *client, u32 load,
1261b47b79d8SRamesh Shanmugasundaram 				       u32 *bits)
1262b47b79d8SRamesh Shanmugasundaram {
12638ca00927SMauro Carvalho Chehab 	if (load <= 40)
1264b47b79d8SRamesh Shanmugasundaram 		*bits = load / 10;
1265b47b79d8SRamesh Shanmugasundaram 	else if (load >= 60 && load <= 70)
1266b47b79d8SRamesh Shanmugasundaram 		*bits = load / 10 - 1;
1267b47b79d8SRamesh Shanmugasundaram 	else
1268b47b79d8SRamesh Shanmugasundaram 		return -EINVAL;
1269b47b79d8SRamesh Shanmugasundaram 
1270b47b79d8SRamesh Shanmugasundaram 	return 0;
1271b47b79d8SRamesh Shanmugasundaram }
1272b47b79d8SRamesh Shanmugasundaram 
max2175_probe(struct i2c_client * client)1273e6714993SKieran Bingham static int max2175_probe(struct i2c_client *client)
1274b47b79d8SRamesh Shanmugasundaram {
1275b47b79d8SRamesh Shanmugasundaram 	bool master = true, am_hiz = false;
1276b47b79d8SRamesh Shanmugasundaram 	u32 refout_load, refout_bits = 0;	/* REFOUT disabled */
1277b47b79d8SRamesh Shanmugasundaram 	struct v4l2_ctrl_handler *hdl;
1278b47b79d8SRamesh Shanmugasundaram 	struct fwnode_handle *fwnode;
1279b47b79d8SRamesh Shanmugasundaram 	struct device_node *np;
1280b47b79d8SRamesh Shanmugasundaram 	struct v4l2_subdev *sd;
1281b47b79d8SRamesh Shanmugasundaram 	struct regmap *regmap;
1282b47b79d8SRamesh Shanmugasundaram 	struct max2175 *ctx;
1283b47b79d8SRamesh Shanmugasundaram 	struct clk *clk;
1284b47b79d8SRamesh Shanmugasundaram 	int ret;
1285b47b79d8SRamesh Shanmugasundaram 
1286b47b79d8SRamesh Shanmugasundaram 	/* Parse DT properties */
1287b47b79d8SRamesh Shanmugasundaram 	np = of_parse_phandle(client->dev.of_node, "maxim,master", 0);
1288b47b79d8SRamesh Shanmugasundaram 	if (np) {
1289b47b79d8SRamesh Shanmugasundaram 		master = false;			/* Slave tuner */
1290b47b79d8SRamesh Shanmugasundaram 		of_node_put(np);
1291b47b79d8SRamesh Shanmugasundaram 	}
1292b47b79d8SRamesh Shanmugasundaram 
1293b47b79d8SRamesh Shanmugasundaram 	fwnode = of_fwnode_handle(client->dev.of_node);
1294b47b79d8SRamesh Shanmugasundaram 	if (fwnode_property_present(fwnode, "maxim,am-hiz-filter"))
1295b47b79d8SRamesh Shanmugasundaram 		am_hiz = true;
1296b47b79d8SRamesh Shanmugasundaram 
1297b47b79d8SRamesh Shanmugasundaram 	if (!fwnode_property_read_u32(fwnode, "maxim,refout-load",
1298b47b79d8SRamesh Shanmugasundaram 				      &refout_load)) {
1299b47b79d8SRamesh Shanmugasundaram 		ret = max2175_refout_load_to_bits(client, refout_load,
1300b47b79d8SRamesh Shanmugasundaram 						  &refout_bits);
1301b47b79d8SRamesh Shanmugasundaram 		if (ret) {
1302b47b79d8SRamesh Shanmugasundaram 			dev_err(&client->dev, "invalid refout_load %u\n",
1303b47b79d8SRamesh Shanmugasundaram 				refout_load);
1304b47b79d8SRamesh Shanmugasundaram 			return -EINVAL;
1305b47b79d8SRamesh Shanmugasundaram 		}
1306b47b79d8SRamesh Shanmugasundaram 	}
1307b47b79d8SRamesh Shanmugasundaram 
1308b47b79d8SRamesh Shanmugasundaram 	clk = devm_clk_get(&client->dev, NULL);
1309b47b79d8SRamesh Shanmugasundaram 	if (IS_ERR(clk)) {
1310b47b79d8SRamesh Shanmugasundaram 		ret = PTR_ERR(clk);
1311b47b79d8SRamesh Shanmugasundaram 		dev_err(&client->dev, "cannot get clock %d\n", ret);
13129a45bf28SFabio Estevam 		return ret;
1313b47b79d8SRamesh Shanmugasundaram 	}
1314b47b79d8SRamesh Shanmugasundaram 
1315b47b79d8SRamesh Shanmugasundaram 	regmap = devm_regmap_init_i2c(client, &max2175_regmap_config);
1316b47b79d8SRamesh Shanmugasundaram 	if (IS_ERR(regmap)) {
1317b47b79d8SRamesh Shanmugasundaram 		ret = PTR_ERR(regmap);
1318b47b79d8SRamesh Shanmugasundaram 		dev_err(&client->dev, "regmap init failed %d\n", ret);
1319b47b79d8SRamesh Shanmugasundaram 		return -ENODEV;
1320b47b79d8SRamesh Shanmugasundaram 	}
1321b47b79d8SRamesh Shanmugasundaram 
1322b47b79d8SRamesh Shanmugasundaram 	/* Alloc tuner context */
1323b47b79d8SRamesh Shanmugasundaram 	ctx = devm_kzalloc(&client->dev, sizeof(*ctx), GFP_KERNEL);
1324b47b79d8SRamesh Shanmugasundaram 	if (ctx == NULL)
1325b47b79d8SRamesh Shanmugasundaram 		return -ENOMEM;
1326b47b79d8SRamesh Shanmugasundaram 
1327b47b79d8SRamesh Shanmugasundaram 	sd = &ctx->sd;
1328b47b79d8SRamesh Shanmugasundaram 	ctx->master = master;
1329b47b79d8SRamesh Shanmugasundaram 	ctx->am_hiz = am_hiz;
1330b47b79d8SRamesh Shanmugasundaram 	ctx->mode_resolved = false;
1331b47b79d8SRamesh Shanmugasundaram 	ctx->regmap = regmap;
1332b47b79d8SRamesh Shanmugasundaram 	ctx->xtal_freq = clk_get_rate(clk);
1333b47b79d8SRamesh Shanmugasundaram 	dev_info(&client->dev, "xtal freq %luHz\n", ctx->xtal_freq);
1334b47b79d8SRamesh Shanmugasundaram 
1335b47b79d8SRamesh Shanmugasundaram 	v4l2_i2c_subdev_init(sd, client, &max2175_ops);
1336b47b79d8SRamesh Shanmugasundaram 	ctx->client = client;
1337b47b79d8SRamesh Shanmugasundaram 
1338baf1b186SAkinobu Mita 	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
1339b47b79d8SRamesh Shanmugasundaram 
1340b47b79d8SRamesh Shanmugasundaram 	/* Controls */
1341b47b79d8SRamesh Shanmugasundaram 	hdl = &ctx->ctrl_hdl;
1342b47b79d8SRamesh Shanmugasundaram 	ret = v4l2_ctrl_handler_init(hdl, 7);
1343b47b79d8SRamesh Shanmugasundaram 	if (ret)
1344b47b79d8SRamesh Shanmugasundaram 		return ret;
1345b47b79d8SRamesh Shanmugasundaram 
1346b47b79d8SRamesh Shanmugasundaram 	ctx->lna_gain = v4l2_ctrl_new_std(hdl, &max2175_ctrl_ops,
1347b47b79d8SRamesh Shanmugasundaram 					  V4L2_CID_RF_TUNER_LNA_GAIN,
1348b47b79d8SRamesh Shanmugasundaram 					  0, 63, 1, 0);
1349b47b79d8SRamesh Shanmugasundaram 	ctx->lna_gain->flags |= (V4L2_CTRL_FLAG_VOLATILE |
1350b47b79d8SRamesh Shanmugasundaram 				 V4L2_CTRL_FLAG_READ_ONLY);
1351b47b79d8SRamesh Shanmugasundaram 	ctx->if_gain = v4l2_ctrl_new_std(hdl, &max2175_ctrl_ops,
1352b47b79d8SRamesh Shanmugasundaram 					 V4L2_CID_RF_TUNER_IF_GAIN,
1353b47b79d8SRamesh Shanmugasundaram 					 0, 31, 1, 0);
1354b47b79d8SRamesh Shanmugasundaram 	ctx->if_gain->flags |= (V4L2_CTRL_FLAG_VOLATILE |
1355b47b79d8SRamesh Shanmugasundaram 				V4L2_CTRL_FLAG_READ_ONLY);
1356b47b79d8SRamesh Shanmugasundaram 	ctx->pll_lock = v4l2_ctrl_new_std(hdl, &max2175_ctrl_ops,
1357b47b79d8SRamesh Shanmugasundaram 					  V4L2_CID_RF_TUNER_PLL_LOCK,
1358b47b79d8SRamesh Shanmugasundaram 					  0, 1, 1, 0);
1359b47b79d8SRamesh Shanmugasundaram 	ctx->pll_lock->flags |= (V4L2_CTRL_FLAG_VOLATILE |
1360b47b79d8SRamesh Shanmugasundaram 				 V4L2_CTRL_FLAG_READ_ONLY);
1361b47b79d8SRamesh Shanmugasundaram 	ctx->i2s_en = v4l2_ctrl_new_custom(hdl, &max2175_i2s_en, NULL);
1362b47b79d8SRamesh Shanmugasundaram 	ctx->hsls = v4l2_ctrl_new_custom(hdl, &max2175_hsls, NULL);
1363b47b79d8SRamesh Shanmugasundaram 
1364b47b79d8SRamesh Shanmugasundaram 	if (ctx->xtal_freq == MAX2175_EU_XTAL_FREQ) {
1365b47b79d8SRamesh Shanmugasundaram 		ctx->rx_mode = v4l2_ctrl_new_custom(hdl,
1366b47b79d8SRamesh Shanmugasundaram 						    &max2175_eu_rx_mode, NULL);
1367b47b79d8SRamesh Shanmugasundaram 		ctx->rx_modes = eu_rx_modes;
1368b47b79d8SRamesh Shanmugasundaram 		ctx->bands_rf = &eu_bands_rf;
1369b47b79d8SRamesh Shanmugasundaram 	} else {
1370b47b79d8SRamesh Shanmugasundaram 		ctx->rx_mode = v4l2_ctrl_new_custom(hdl,
1371b47b79d8SRamesh Shanmugasundaram 						    &max2175_na_rx_mode, NULL);
1372b47b79d8SRamesh Shanmugasundaram 		ctx->rx_modes = na_rx_modes;
1373b47b79d8SRamesh Shanmugasundaram 		ctx->bands_rf = &na_bands_rf;
1374b47b79d8SRamesh Shanmugasundaram 	}
1375b47b79d8SRamesh Shanmugasundaram 	ctx->sd.ctrl_handler = &ctx->ctrl_hdl;
1376b47b79d8SRamesh Shanmugasundaram 
1377b47b79d8SRamesh Shanmugasundaram 	/* Set the defaults */
1378b47b79d8SRamesh Shanmugasundaram 	ctx->freq = ctx->bands_rf->rangelow;
1379b47b79d8SRamesh Shanmugasundaram 
1380b47b79d8SRamesh Shanmugasundaram 	/* Register subdev */
1381b47b79d8SRamesh Shanmugasundaram 	ret = v4l2_async_register_subdev(sd);
1382b47b79d8SRamesh Shanmugasundaram 	if (ret) {
1383b47b79d8SRamesh Shanmugasundaram 		dev_err(&client->dev, "register subdev failed\n");
1384b47b79d8SRamesh Shanmugasundaram 		goto err_reg;
1385b47b79d8SRamesh Shanmugasundaram 	}
1386b47b79d8SRamesh Shanmugasundaram 
1387b47b79d8SRamesh Shanmugasundaram 	/* Initialize device */
1388b47b79d8SRamesh Shanmugasundaram 	ret = max2175_core_init(ctx, refout_bits);
1389b47b79d8SRamesh Shanmugasundaram 	if (ret)
1390b47b79d8SRamesh Shanmugasundaram 		goto err_init;
1391b47b79d8SRamesh Shanmugasundaram 
1392b47b79d8SRamesh Shanmugasundaram 	ret = v4l2_ctrl_handler_setup(hdl);
1393b47b79d8SRamesh Shanmugasundaram 	if (ret)
1394b47b79d8SRamesh Shanmugasundaram 		goto err_init;
1395b47b79d8SRamesh Shanmugasundaram 
1396b47b79d8SRamesh Shanmugasundaram 	return 0;
1397b47b79d8SRamesh Shanmugasundaram 
1398b47b79d8SRamesh Shanmugasundaram err_init:
1399b47b79d8SRamesh Shanmugasundaram 	v4l2_async_unregister_subdev(sd);
1400b47b79d8SRamesh Shanmugasundaram err_reg:
1401b47b79d8SRamesh Shanmugasundaram 	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
1402b47b79d8SRamesh Shanmugasundaram 
1403b47b79d8SRamesh Shanmugasundaram 	return ret;
1404b47b79d8SRamesh Shanmugasundaram }
1405b47b79d8SRamesh Shanmugasundaram 
max2175_remove(struct i2c_client * client)1406ed5c2f5fSUwe Kleine-König static void max2175_remove(struct i2c_client *client)
1407b47b79d8SRamesh Shanmugasundaram {
1408b47b79d8SRamesh Shanmugasundaram 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
1409b47b79d8SRamesh Shanmugasundaram 	struct max2175 *ctx = max2175_from_sd(sd);
1410b47b79d8SRamesh Shanmugasundaram 
1411b47b79d8SRamesh Shanmugasundaram 	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
1412b47b79d8SRamesh Shanmugasundaram 	v4l2_async_unregister_subdev(sd);
1413b47b79d8SRamesh Shanmugasundaram }
1414b47b79d8SRamesh Shanmugasundaram 
1415b47b79d8SRamesh Shanmugasundaram static const struct i2c_device_id max2175_id[] = {
1416b47b79d8SRamesh Shanmugasundaram 	{ DRIVER_NAME, 0},
1417b47b79d8SRamesh Shanmugasundaram 	{},
1418b47b79d8SRamesh Shanmugasundaram };
1419b47b79d8SRamesh Shanmugasundaram MODULE_DEVICE_TABLE(i2c, max2175_id);
1420b47b79d8SRamesh Shanmugasundaram 
1421b47b79d8SRamesh Shanmugasundaram static const struct of_device_id max2175_of_ids[] = {
1422b47b79d8SRamesh Shanmugasundaram 	{ .compatible = "maxim,max2175", },
1423b47b79d8SRamesh Shanmugasundaram 	{ }
1424b47b79d8SRamesh Shanmugasundaram };
1425b47b79d8SRamesh Shanmugasundaram MODULE_DEVICE_TABLE(of, max2175_of_ids);
1426b47b79d8SRamesh Shanmugasundaram 
1427b47b79d8SRamesh Shanmugasundaram static struct i2c_driver max2175_driver = {
1428b47b79d8SRamesh Shanmugasundaram 	.driver = {
1429b47b79d8SRamesh Shanmugasundaram 		.name	= DRIVER_NAME,
1430b47b79d8SRamesh Shanmugasundaram 		.of_match_table = max2175_of_ids,
1431b47b79d8SRamesh Shanmugasundaram 	},
1432*aaeb31c0SUwe Kleine-König 	.probe		= max2175_probe,
1433b47b79d8SRamesh Shanmugasundaram 	.remove		= max2175_remove,
1434b47b79d8SRamesh Shanmugasundaram 	.id_table	= max2175_id,
1435b47b79d8SRamesh Shanmugasundaram };
1436b47b79d8SRamesh Shanmugasundaram 
1437b47b79d8SRamesh Shanmugasundaram module_i2c_driver(max2175_driver);
1438b47b79d8SRamesh Shanmugasundaram 
1439b47b79d8SRamesh Shanmugasundaram MODULE_DESCRIPTION("Maxim MAX2175 RF to Bits tuner driver");
1440b47b79d8SRamesh Shanmugasundaram MODULE_LICENSE("GPL v2");
1441b47b79d8SRamesh Shanmugasundaram MODULE_AUTHOR("Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>");
1442