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 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 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 */ 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 */ 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, ®val); 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1406*ed5c2f5fSUwe 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 }, 1432e6714993SKieran Bingham .probe_new = 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