162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  drivers/media/radio/si470x/radio-si470x.h
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Driver for radios with Silicon Labs Si470x FM Radio Receivers
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* driver definitions */
1262306a36Sopenharmony_ci#define DRIVER_NAME "radio-si470x"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* kernel includes */
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/init.h>
1962306a36Sopenharmony_ci#include <linux/sched.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/input.h>
2262306a36Sopenharmony_ci#include <linux/videodev2.h>
2362306a36Sopenharmony_ci#include <linux/mutex.h>
2462306a36Sopenharmony_ci#include <media/v4l2-common.h>
2562306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
2662306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
2762306a36Sopenharmony_ci#include <media/v4l2-event.h>
2862306a36Sopenharmony_ci#include <media/v4l2-device.h>
2962306a36Sopenharmony_ci#include <asm/unaligned.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/**************************************************************************
3462306a36Sopenharmony_ci * Register Definitions
3562306a36Sopenharmony_ci **************************************************************************/
3662306a36Sopenharmony_ci#define RADIO_REGISTER_SIZE	2	/* 16 register bit width */
3762306a36Sopenharmony_ci#define RADIO_REGISTER_NUM	16	/* DEVICEID   ... RDSD */
3862306a36Sopenharmony_ci#define RDS_REGISTER_NUM	6	/* STATUSRSSI ... RDSD */
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define DEVICEID		0	/* Device ID */
4162306a36Sopenharmony_ci#define DEVICEID_PN		0xf000	/* bits 15..12: Part Number */
4262306a36Sopenharmony_ci#define DEVICEID_MFGID		0x0fff	/* bits 11..00: Manufacturer ID */
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define SI_CHIPID		1	/* Chip ID */
4562306a36Sopenharmony_ci#define SI_CHIPID_REV		0xfc00	/* bits 15..10: Chip Version */
4662306a36Sopenharmony_ci#define SI_CHIPID_DEV		0x0200	/* bits 09..09: Device */
4762306a36Sopenharmony_ci#define SI_CHIPID_FIRMWARE	0x01ff	/* bits 08..00: Firmware Version */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define POWERCFG		2	/* Power Configuration */
5062306a36Sopenharmony_ci#define POWERCFG_DSMUTE		0x8000	/* bits 15..15: Softmute Disable */
5162306a36Sopenharmony_ci#define POWERCFG_DMUTE		0x4000	/* bits 14..14: Mute Disable */
5262306a36Sopenharmony_ci#define POWERCFG_MONO		0x2000	/* bits 13..13: Mono Select */
5362306a36Sopenharmony_ci#define POWERCFG_RDSM		0x0800	/* bits 11..11: RDS Mode (Si4701 only) */
5462306a36Sopenharmony_ci#define POWERCFG_SKMODE		0x0400	/* bits 10..10: Seek Mode */
5562306a36Sopenharmony_ci#define POWERCFG_SEEKUP		0x0200	/* bits 09..09: Seek Direction */
5662306a36Sopenharmony_ci#define POWERCFG_SEEK		0x0100	/* bits 08..08: Seek */
5762306a36Sopenharmony_ci#define POWERCFG_DISABLE	0x0040	/* bits 06..06: Powerup Disable */
5862306a36Sopenharmony_ci#define POWERCFG_ENABLE		0x0001	/* bits 00..00: Powerup Enable */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define CHANNEL			3	/* Channel */
6162306a36Sopenharmony_ci#define CHANNEL_TUNE		0x8000	/* bits 15..15: Tune */
6262306a36Sopenharmony_ci#define CHANNEL_CHAN		0x03ff	/* bits 09..00: Channel Select */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define SYSCONFIG1		4	/* System Configuration 1 */
6562306a36Sopenharmony_ci#define SYSCONFIG1_RDSIEN	0x8000	/* bits 15..15: RDS Interrupt Enable (Si4701 only) */
6662306a36Sopenharmony_ci#define SYSCONFIG1_STCIEN	0x4000	/* bits 14..14: Seek/Tune Complete Interrupt Enable */
6762306a36Sopenharmony_ci#define SYSCONFIG1_RDS		0x1000	/* bits 12..12: RDS Enable (Si4701 only) */
6862306a36Sopenharmony_ci#define SYSCONFIG1_DE		0x0800	/* bits 11..11: De-emphasis (0=75us 1=50us) */
6962306a36Sopenharmony_ci#define SYSCONFIG1_AGCD		0x0400	/* bits 10..10: AGC Disable */
7062306a36Sopenharmony_ci#define SYSCONFIG1_BLNDADJ	0x00c0	/* bits 07..06: Stereo/Mono Blend Level Adjustment */
7162306a36Sopenharmony_ci#define SYSCONFIG1_GPIO3	0x0030	/* bits 05..04: General Purpose I/O 3 */
7262306a36Sopenharmony_ci#define SYSCONFIG1_GPIO2	0x000c	/* bits 03..02: General Purpose I/O 2 */
7362306a36Sopenharmony_ci#define SYSCONFIG1_GPIO2_DIS	0x0000	/* Disable GPIO 2 interrupt */
7462306a36Sopenharmony_ci#define SYSCONFIG1_GPIO2_INT	0x0004	/* Enable STC/RDS interrupt */
7562306a36Sopenharmony_ci#define SYSCONFIG1_GPIO1	0x0003	/* bits 01..00: General Purpose I/O 1 */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define SYSCONFIG2		5	/* System Configuration 2 */
7862306a36Sopenharmony_ci#define SYSCONFIG2_SEEKTH	0xff00	/* bits 15..08: RSSI Seek Threshold */
7962306a36Sopenharmony_ci#define SYSCONFIG2_BAND		0x00c0	/* bits 07..06: Band Select */
8062306a36Sopenharmony_ci#define SYSCONFIG2_SPACE	0x0030	/* bits 05..04: Channel Spacing */
8162306a36Sopenharmony_ci#define SYSCONFIG2_VOLUME	0x000f	/* bits 03..00: Volume */
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define SYSCONFIG3		6	/* System Configuration 3 */
8462306a36Sopenharmony_ci#define SYSCONFIG3_SMUTER	0xc000	/* bits 15..14: Softmute Attack/Recover Rate */
8562306a36Sopenharmony_ci#define SYSCONFIG3_SMUTEA	0x3000	/* bits 13..12: Softmute Attenuation */
8662306a36Sopenharmony_ci#define SYSCONFIG3_SKSNR	0x00f0	/* bits 07..04: Seek SNR Threshold */
8762306a36Sopenharmony_ci#define SYSCONFIG3_SKCNT	0x000f	/* bits 03..00: Seek FM Impulse Detection Threshold */
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define TEST1			7	/* Test 1 */
9062306a36Sopenharmony_ci#define TEST1_AHIZEN		0x4000	/* bits 14..14: Audio High-Z Enable */
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define TEST2			8	/* Test 2 */
9362306a36Sopenharmony_ci/* TEST2 only contains reserved bits */
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define BOOTCONFIG		9	/* Boot Configuration */
9662306a36Sopenharmony_ci/* BOOTCONFIG only contains reserved bits */
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define STATUSRSSI		10	/* Status RSSI */
9962306a36Sopenharmony_ci#define STATUSRSSI_RDSR		0x8000	/* bits 15..15: RDS Ready (Si4701 only) */
10062306a36Sopenharmony_ci#define STATUSRSSI_STC		0x4000	/* bits 14..14: Seek/Tune Complete */
10162306a36Sopenharmony_ci#define STATUSRSSI_SF		0x2000	/* bits 13..13: Seek Fail/Band Limit */
10262306a36Sopenharmony_ci#define STATUSRSSI_AFCRL	0x1000	/* bits 12..12: AFC Rail */
10362306a36Sopenharmony_ci#define STATUSRSSI_RDSS		0x0800	/* bits 11..11: RDS Synchronized (Si4701 only) */
10462306a36Sopenharmony_ci#define STATUSRSSI_BLERA	0x0600	/* bits 10..09: RDS Block A Errors (Si4701 only) */
10562306a36Sopenharmony_ci#define STATUSRSSI_ST		0x0100	/* bits 08..08: Stereo Indicator */
10662306a36Sopenharmony_ci#define STATUSRSSI_RSSI		0x00ff	/* bits 07..00: RSSI (Received Signal Strength Indicator) */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define READCHAN		11	/* Read Channel */
10962306a36Sopenharmony_ci#define READCHAN_BLERB		0xc000	/* bits 15..14: RDS Block D Errors (Si4701 only) */
11062306a36Sopenharmony_ci#define READCHAN_BLERC		0x3000	/* bits 13..12: RDS Block C Errors (Si4701 only) */
11162306a36Sopenharmony_ci#define READCHAN_BLERD		0x0c00	/* bits 11..10: RDS Block B Errors (Si4701 only) */
11262306a36Sopenharmony_ci#define READCHAN_READCHAN	0x03ff	/* bits 09..00: Read Channel */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci#define RDSA			12	/* RDSA */
11562306a36Sopenharmony_ci#define RDSA_RDSA		0xffff	/* bits 15..00: RDS Block A Data (Si4701 only) */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#define RDSB			13	/* RDSB */
11862306a36Sopenharmony_ci#define RDSB_RDSB		0xffff	/* bits 15..00: RDS Block B Data (Si4701 only) */
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define RDSC			14	/* RDSC */
12162306a36Sopenharmony_ci#define RDSC_RDSC		0xffff	/* bits 15..00: RDS Block C Data (Si4701 only) */
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define RDSD			15	/* RDSD */
12462306a36Sopenharmony_ci#define RDSD_RDSD		0xffff	/* bits 15..00: RDS Block D Data (Si4701 only) */
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/**************************************************************************
12962306a36Sopenharmony_ci * General Driver Definitions
13062306a36Sopenharmony_ci **************************************************************************/
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/*
13362306a36Sopenharmony_ci * si470x_device - private data
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_cistruct si470x_device {
13662306a36Sopenharmony_ci	struct v4l2_device v4l2_dev;
13762306a36Sopenharmony_ci	struct video_device videodev;
13862306a36Sopenharmony_ci	struct v4l2_ctrl_handler hdl;
13962306a36Sopenharmony_ci	int band;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* Silabs internal registers (0..15) */
14262306a36Sopenharmony_ci	unsigned short registers[RADIO_REGISTER_NUM];
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* RDS receive buffer */
14562306a36Sopenharmony_ci	wait_queue_head_t read_queue;
14662306a36Sopenharmony_ci	struct mutex lock;		/* buffer locking */
14762306a36Sopenharmony_ci	unsigned char *buffer;		/* size is always multiple of three */
14862306a36Sopenharmony_ci	unsigned int buf_size;
14962306a36Sopenharmony_ci	unsigned int rd_index;
15062306a36Sopenharmony_ci	unsigned int wr_index;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	struct completion completion;
15362306a36Sopenharmony_ci	bool status_rssi_auto_update;	/* Does RSSI get updated automatic? */
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* si470x ops */
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	int (*get_register)(struct si470x_device *radio, int regnr);
15862306a36Sopenharmony_ci	int (*set_register)(struct si470x_device *radio, int regnr);
15962306a36Sopenharmony_ci	int (*fops_open)(struct file *file);
16062306a36Sopenharmony_ci	int (*fops_release)(struct file *file);
16162306a36Sopenharmony_ci	int (*vidioc_querycap)(struct file *file, void *priv,
16262306a36Sopenharmony_ci			       struct v4l2_capability *capability);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_USB_SI470X)
16562306a36Sopenharmony_ci	/* reference to USB and video device */
16662306a36Sopenharmony_ci	struct usb_device *usbdev;
16762306a36Sopenharmony_ci	struct usb_interface *intf;
16862306a36Sopenharmony_ci	char *usb_buf;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* Interrupt endpoint handling */
17162306a36Sopenharmony_ci	char *int_in_buffer;
17262306a36Sopenharmony_ci	struct usb_endpoint_descriptor *int_in_endpoint;
17362306a36Sopenharmony_ci	struct urb *int_in_urb;
17462306a36Sopenharmony_ci	int int_in_running;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	/* scratch page */
17762306a36Sopenharmony_ci	unsigned char software_version;
17862306a36Sopenharmony_ci	unsigned char hardware_version;
17962306a36Sopenharmony_ci#endif
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_I2C_SI470X)
18262306a36Sopenharmony_ci	struct i2c_client *client;
18362306a36Sopenharmony_ci	struct gpio_desc *gpio_reset;
18462306a36Sopenharmony_ci#endif
18562306a36Sopenharmony_ci};
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/**************************************************************************
19062306a36Sopenharmony_ci * Firmware Versions
19162306a36Sopenharmony_ci **************************************************************************/
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci#define RADIO_FW_VERSION	12
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci/**************************************************************************
19862306a36Sopenharmony_ci * Frequency Multiplicator
19962306a36Sopenharmony_ci **************************************************************************/
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/*
20262306a36Sopenharmony_ci * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
20362306a36Sopenharmony_ci * 62.5 kHz otherwise.
20462306a36Sopenharmony_ci * The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
20562306a36Sopenharmony_ci * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
20662306a36Sopenharmony_ci * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
20762306a36Sopenharmony_ci */
20862306a36Sopenharmony_ci#define FREQ_MUL (1000000 / 62.5)
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/**************************************************************************
21362306a36Sopenharmony_ci * Common Functions
21462306a36Sopenharmony_ci **************************************************************************/
21562306a36Sopenharmony_ciextern const struct video_device si470x_viddev_template;
21662306a36Sopenharmony_ciextern const struct v4l2_ctrl_ops si470x_ctrl_ops;
21762306a36Sopenharmony_ciint si470x_disconnect_check(struct si470x_device *radio);
21862306a36Sopenharmony_ciint si470x_set_freq(struct si470x_device *radio, unsigned int freq);
21962306a36Sopenharmony_ciint si470x_start(struct si470x_device *radio);
22062306a36Sopenharmony_ciint si470x_stop(struct si470x_device *radio);
221