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