^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * driver/media/radio/radio-tea5764.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Driver for TEA5764 radio chip for linux 2.6.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This driver is for TEA5764 chip from NXP, used in EZX phones from Motorola.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * The I2C protocol is used for communicate with chip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Based in radio-tea5761.c Copyright (C) 2005 Nokia Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Copyright (c) 2008 Fabio Belavenuto <belavenuto@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * History:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * 2008-12-06 Fabio Belavenuto <belavenuto@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * initial code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * TODO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * add platform_data support for IRQs platform dependencies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * add RDS support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/init.h> /* Initdata */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/videodev2.h> /* kernel radio structs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/i2c.h> /* I2C */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <media/v4l2-common.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <media/v4l2-ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <media/v4l2-device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <media/v4l2-ctrls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <media/v4l2-event.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define DRIVER_VERSION "0.0.2"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define DRIVER_AUTHOR "Fabio Belavenuto <belavenuto@gmail.com>"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define DRIVER_DESC "A driver for the TEA5764 radio chip for EZX Phones."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define PINFO(format, ...)\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) printk(KERN_INFO KBUILD_MODNAME ": "\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) DRIVER_VERSION ": " format "\n", ## __VA_ARGS__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define PWARN(format, ...)\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) printk(KERN_WARNING KBUILD_MODNAME ": "\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) DRIVER_VERSION ": " format "\n", ## __VA_ARGS__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) # define PDEBUG(format, ...)\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) printk(KERN_DEBUG KBUILD_MODNAME ": "\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) DRIVER_VERSION ": " format "\n", ## __VA_ARGS__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /* Frequency limits in MHz -- these are European values. For Japanese
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) devices, that would be 76000 and 91000. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define FREQ_MIN 87500U
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define FREQ_MAX 108000U
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define FREQ_MUL 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* TEA5764 registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define TEA5764_MANID 0x002b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define TEA5764_CHIPID 0x5764
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define TEA5764_INTREG_BLMSK 0x0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define TEA5764_INTREG_FRRMSK 0x0002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define TEA5764_INTREG_LEVMSK 0x0008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define TEA5764_INTREG_IFMSK 0x0010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define TEA5764_INTREG_BLMFLAG 0x0100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define TEA5764_INTREG_FRRFLAG 0x0200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define TEA5764_INTREG_LEVFLAG 0x0800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define TEA5764_INTREG_IFFLAG 0x1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define TEA5764_FRQSET_SUD 0x8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define TEA5764_FRQSET_SM 0x4000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define TEA5764_TNCTRL_PUPD1 0x8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define TEA5764_TNCTRL_PUPD0 0x4000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define TEA5764_TNCTRL_BLIM 0x2000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define TEA5764_TNCTRL_SWPM 0x1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define TEA5764_TNCTRL_IFCTC 0x0800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define TEA5764_TNCTRL_AFM 0x0400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define TEA5764_TNCTRL_SMUTE 0x0200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define TEA5764_TNCTRL_SNC 0x0100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define TEA5764_TNCTRL_MU 0x0080
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define TEA5764_TNCTRL_SSL1 0x0040
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define TEA5764_TNCTRL_SSL0 0x0020
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define TEA5764_TNCTRL_HLSI 0x0010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define TEA5764_TNCTRL_MST 0x0008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define TEA5764_TNCTRL_SWP 0x0004
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define TEA5764_TNCTRL_DTC 0x0002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define TEA5764_TNCTRL_AHLSI 0x0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define TEA5764_TUNCHK_LEVEL(x) (((x) & 0x00F0) >> 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define TEA5764_TUNCHK_IFCNT(x) (((x) & 0xFE00) >> 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define TEA5764_TUNCHK_TUNTO 0x0100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define TEA5764_TUNCHK_LD 0x0008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define TEA5764_TUNCHK_STEREO 0x0004
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define TEA5764_TESTREG_TRIGFR 0x0800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct tea5764_regs {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) u16 intreg; /* INTFLAG & INTMSK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u16 frqset; /* FRQSETMSB & FRQSETLSB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) u16 tnctrl; /* TNCTRL1 & TNCTRL2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) u16 frqchk; /* FRQCHKMSB & FRQCHKLSB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) u16 tunchk; /* IFCHK & LEVCHK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u16 testreg; /* TESTBITS & TESTMODE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) u16 rdsstat; /* RDSSTAT1 & RDSSTAT2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) u16 rdslb; /* RDSLBMSB & RDSLBLSB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) u16 rdspb; /* RDSPBMSB & RDSPBLSB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) u16 rdsbc; /* RDSBBC & RDSGBC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) u16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) u16 rdsbbl; /* PAUSEDET & RDSBBL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) u16 manid; /* MANID1 & MANID2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) u16 chipid; /* CHIPID1 & CHIPID2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) } __attribute__ ((packed));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct tea5764_write_regs {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) u8 intreg; /* INTMSK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) __be16 frqset; /* FRQSETMSB & FRQSETLSB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) __be16 tnctrl; /* TNCTRL1 & TNCTRL2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) __be16 testreg; /* TESTBITS & TESTMODE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) __be16 rdsctrl; /* RDSCTRL1 & RDSCTRL2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) __be16 rdsbbl; /* PAUSEDET & RDSBBL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) } __attribute__ ((packed));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #ifdef CONFIG_RADIO_TEA5764_XTAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define RADIO_TEA5764_XTAL 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define RADIO_TEA5764_XTAL 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) static int radio_nr = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static int use_xtal = RADIO_TEA5764_XTAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct tea5764_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct v4l2_device v4l2_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct v4l2_ctrl_handler ctrl_handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct i2c_client *i2c_client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct video_device vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct tea5764_regs regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct mutex mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* I2C code related */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static int tea5764_i2c_read(struct tea5764_device *radio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) u16 *p = (u16 *) &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct i2c_msg msgs[1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) { .addr = radio->i2c_client->addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .flags = I2C_M_RD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .len = sizeof(radio->regs),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) .buf = (void *)&radio->regs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) for (i = 0; i < sizeof(struct tea5764_regs) / sizeof(u16); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) p[i] = __be16_to_cpu((__force __be16)p[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static int tea5764_i2c_write(struct tea5764_device *radio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct tea5764_write_regs wr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) struct i2c_msg msgs[1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) .addr = radio->i2c_client->addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .len = sizeof(wr),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .buf = (void *)&wr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) wr.intreg = r->intreg & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) wr.frqset = __cpu_to_be16(r->frqset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) wr.tnctrl = __cpu_to_be16(r->tnctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) wr.testreg = __cpu_to_be16(r->testreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) wr.rdsctrl = __cpu_to_be16(r->rdsctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) wr.rdsbbl = __cpu_to_be16(r->rdsbbl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (i2c_transfer(radio->i2c_client->adapter, msgs, 1) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static void tea5764_power_up(struct tea5764_device *radio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (!(r->tnctrl & TEA5764_TNCTRL_PUPD0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) r->tnctrl &= ~(TEA5764_TNCTRL_AFM | TEA5764_TNCTRL_MU |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) TEA5764_TNCTRL_HLSI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (!use_xtal)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) r->testreg |= TEA5764_TESTREG_TRIGFR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) r->testreg &= ~TEA5764_TESTREG_TRIGFR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) r->tnctrl |= TEA5764_TNCTRL_PUPD0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) tea5764_i2c_write(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static void tea5764_power_down(struct tea5764_device *radio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (r->tnctrl & TEA5764_TNCTRL_PUPD0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) r->tnctrl &= ~TEA5764_TNCTRL_PUPD0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) tea5764_i2c_write(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static void tea5764_set_freq(struct tea5764_device *radio, int freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /* formula: (freq [+ or -] 225000) / 8192 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (r->tnctrl & TEA5764_TNCTRL_HLSI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) r->frqset = (freq + 225000) / 8192;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) r->frqset = (freq - 225000) / 8192;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) static int tea5764_get_freq(struct tea5764_device *radio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) if (r->tnctrl & TEA5764_TNCTRL_HLSI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return (r->frqchk * 8192) - 225000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) return (r->frqchk * 8192) + 225000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /* tune an frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static void tea5764_tune(struct tea5764_device *radio, int freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) tea5764_set_freq(radio, freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (tea5764_i2c_write(radio))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) PWARN("Could not set frequency!");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) static void tea5764_set_audout_mode(struct tea5764_device *radio, int audmode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) int tnctrl = r->tnctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (audmode == V4L2_TUNER_MODE_MONO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) r->tnctrl |= TEA5764_TNCTRL_MST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) r->tnctrl &= ~TEA5764_TNCTRL_MST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (tnctrl != r->tnctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) tea5764_i2c_write(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) static int tea5764_get_audout_mode(struct tea5764_device *radio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (r->tnctrl & TEA5764_TNCTRL_MST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return V4L2_TUNER_MODE_MONO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return V4L2_TUNER_MODE_STEREO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static void tea5764_mute(struct tea5764_device *radio, int on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) int tnctrl = r->tnctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) r->tnctrl |= TEA5764_TNCTRL_MU;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) r->tnctrl &= ~TEA5764_TNCTRL_MU;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (tnctrl != r->tnctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) tea5764_i2c_write(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) /* V4L2 vidioc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static int vidioc_querycap(struct file *file, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) struct v4l2_capability *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) struct tea5764_device *radio = video_drvdata(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) struct video_device *dev = &radio->vdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) strscpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) strscpy(v->card, dev->name, sizeof(v->card));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) snprintf(v->bus_info, sizeof(v->bus_info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) "I2C:%s", dev_name(&dev->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) static int vidioc_g_tuner(struct file *file, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) struct v4l2_tuner *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct tea5764_device *radio = video_drvdata(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (v->index > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) strscpy(v->name, "FM", sizeof(v->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) v->type = V4L2_TUNER_RADIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) tea5764_i2c_read(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) v->rangelow = FREQ_MIN * FREQ_MUL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) v->rangehigh = FREQ_MAX * FREQ_MUL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (r->tunchk & TEA5764_TUNCHK_STEREO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) v->rxsubchans = V4L2_TUNER_SUB_STEREO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) v->rxsubchans = V4L2_TUNER_SUB_MONO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) v->audmode = tea5764_get_audout_mode(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) v->signal = TEA5764_TUNCHK_LEVEL(r->tunchk) * 0xffff / 0xf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static int vidioc_s_tuner(struct file *file, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) const struct v4l2_tuner *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) struct tea5764_device *radio = video_drvdata(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (v->index > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) tea5764_set_audout_mode(radio, v->audmode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) static int vidioc_s_frequency(struct file *file, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) const struct v4l2_frequency *f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) struct tea5764_device *radio = video_drvdata(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) unsigned freq = f->frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (freq == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* We special case this as a power down control. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) tea5764_power_down(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /* Yes, that's what is returned in this case. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) whole special case is non-compliant and should really
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) be replaced with something better, but changing this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) might well break code that depends on this behavior.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) So we keep it as-is. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) freq = clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) tea5764_power_up(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) tea5764_tune(radio, (freq * 125) / 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) static int vidioc_g_frequency(struct file *file, void *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) struct v4l2_frequency *f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct tea5764_device *radio = video_drvdata(file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) struct tea5764_regs *r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (f->tuner != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) tea5764_i2c_read(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) f->type = V4L2_TUNER_RADIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (r->tnctrl & TEA5764_TNCTRL_PUPD0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) f->frequency = (tea5764_get_freq(radio) * 2) / 125;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) f->frequency = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) static int tea5764_s_ctrl(struct v4l2_ctrl *ctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) struct tea5764_device *radio =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) container_of(ctrl->handler, struct tea5764_device, ctrl_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) switch (ctrl->id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) case V4L2_CID_AUDIO_MUTE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) tea5764_mute(radio, ctrl->val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static const struct v4l2_ctrl_ops tea5764_ctrl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) .s_ctrl = tea5764_s_ctrl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) /* File system interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) static const struct v4l2_file_operations tea5764_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) .open = v4l2_fh_open,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) .release = v4l2_fh_release,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) .poll = v4l2_ctrl_poll,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) .unlocked_ioctl = video_ioctl2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) .vidioc_querycap = vidioc_querycap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) .vidioc_g_tuner = vidioc_g_tuner,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) .vidioc_s_tuner = vidioc_s_tuner,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) .vidioc_g_frequency = vidioc_g_frequency,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) .vidioc_s_frequency = vidioc_s_frequency,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) .vidioc_log_status = v4l2_ctrl_log_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) /* V4L2 interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) static const struct video_device tea5764_radio_template = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) .name = "TEA5764 FM-Radio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) .fops = &tea5764_fops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) .ioctl_ops = &tea5764_ioctl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) .release = video_device_release_empty,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) /* I2C probe: check if the device exists and register with v4l if it is */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) static int tea5764_i2c_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct tea5764_device *radio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) struct v4l2_device *v4l2_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) struct v4l2_ctrl_handler *hdl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) struct tea5764_regs *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) PDEBUG("probe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if (!radio)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) v4l2_dev = &radio->v4l2_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) ret = v4l2_device_register(&client->dev, v4l2_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) v4l2_err(v4l2_dev, "could not register v4l2_device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) goto errfr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) hdl = &radio->ctrl_handler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) v4l2_ctrl_handler_init(hdl, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) v4l2_ctrl_new_std(hdl, &tea5764_ctrl_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) v4l2_dev->ctrl_handler = hdl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (hdl->error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) ret = hdl->error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) v4l2_err(v4l2_dev, "Could not register controls\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) goto errunreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) mutex_init(&radio->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) radio->i2c_client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) ret = tea5764_i2c_read(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) goto errunreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) r = &radio->regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) PDEBUG("chipid = %04X, manid = %04X", r->chipid, r->manid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (r->chipid != TEA5764_CHIPID ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) (r->manid & 0x0fff) != TEA5764_MANID) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) PWARN("This chip is not a TEA5764!");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) goto errunreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) radio->vdev = tea5764_radio_template;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) i2c_set_clientdata(client, radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) video_set_drvdata(&radio->vdev, radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) radio->vdev.lock = &radio->mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) radio->vdev.v4l2_dev = v4l2_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) radio->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /* initialize and power off the chip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) tea5764_i2c_read(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) tea5764_set_audout_mode(radio, V4L2_TUNER_MODE_STEREO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) tea5764_mute(radio, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) tea5764_power_down(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) ret = video_register_device(&radio->vdev, VFL_TYPE_RADIO, radio_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) PWARN("Could not register video device!");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) goto errunreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) PINFO("registered.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) errunreg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) v4l2_ctrl_handler_free(hdl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) v4l2_device_unregister(v4l2_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) errfr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) kfree(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) static int tea5764_i2c_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) struct tea5764_device *radio = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) PDEBUG("remove");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (radio) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) tea5764_power_down(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) video_unregister_device(&radio->vdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) v4l2_ctrl_handler_free(&radio->ctrl_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) v4l2_device_unregister(&radio->v4l2_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) kfree(radio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /* I2C subsystem interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) static const struct i2c_device_id tea5764_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) { "radio-tea5764", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) { } /* Terminating entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) MODULE_DEVICE_TABLE(i2c, tea5764_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) static struct i2c_driver tea5764_i2c_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) .name = "radio-tea5764",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) .probe = tea5764_i2c_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) .remove = tea5764_i2c_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) .id_table = tea5764_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) module_i2c_driver(tea5764_i2c_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) MODULE_AUTHOR(DRIVER_AUTHOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) MODULE_DESCRIPTION(DRIVER_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) MODULE_VERSION(DRIVER_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) module_param(use_xtal, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) MODULE_PARM_DESC(use_xtal, "Chip have a xtal connected in board");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) module_param(radio_nr, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) MODULE_PARM_DESC(radio_nr, "video4linux device number to use");