root/drivers/media/radio/tef6862.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_state
  2. tef6862_sigstr
  3. tef6862_g_tuner
  4. tef6862_s_tuner
  5. tef6862_s_frequency
  6. tef6862_g_frequency
  7. tef6862_probe
  8. tef6862_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * tef6862.c Philips TEF6862 Car Radio Enhanced Selectivity Tuner
   4  * Copyright (c) 2009 Intel Corporation
   5  */
   6 
   7 #include <linux/module.h>
   8 #include <linux/init.h>
   9 #include <linux/errno.h>
  10 #include <linux/kernel.h>
  11 #include <linux/interrupt.h>
  12 #include <linux/i2c.h>
  13 #include <linux/slab.h>
  14 #include <media/v4l2-ioctl.h>
  15 #include <media/v4l2-device.h>
  16 
  17 #define DRIVER_NAME "tef6862"
  18 
  19 #define FREQ_MUL 16000
  20 
  21 #define TEF6862_LO_FREQ (875U * FREQ_MUL / 10)
  22 #define TEF6862_HI_FREQ (108U * FREQ_MUL)
  23 
  24 /* Write mode sub addresses */
  25 #define WM_SUB_BANDWIDTH        0x0
  26 #define WM_SUB_PLLM             0x1
  27 #define WM_SUB_PLLL             0x2
  28 #define WM_SUB_DAA              0x3
  29 #define WM_SUB_AGC              0x4
  30 #define WM_SUB_BAND             0x5
  31 #define WM_SUB_CONTROL          0x6
  32 #define WM_SUB_LEVEL            0x7
  33 #define WM_SUB_IFCF             0x8
  34 #define WM_SUB_IFCAP            0x9
  35 #define WM_SUB_ACD              0xA
  36 #define WM_SUB_TEST             0xF
  37 
  38 /* Different modes of the MSA register */
  39 #define MSA_MODE_BUFFER         0x0
  40 #define MSA_MODE_PRESET         0x1
  41 #define MSA_MODE_SEARCH         0x2
  42 #define MSA_MODE_AF_UPDATE      0x3
  43 #define MSA_MODE_JUMP           0x4
  44 #define MSA_MODE_CHECK          0x5
  45 #define MSA_MODE_LOAD           0x6
  46 #define MSA_MODE_END            0x7
  47 #define MSA_MODE_SHIFT          5
  48 
  49 struct tef6862_state {
  50         struct v4l2_subdev sd;
  51         unsigned long freq;
  52 };
  53 
  54 static inline struct tef6862_state *to_state(struct v4l2_subdev *sd)
  55 {
  56         return container_of(sd, struct tef6862_state, sd);
  57 }
  58 
  59 static u16 tef6862_sigstr(struct i2c_client *client)
  60 {
  61         u8 buf[4];
  62         int err = i2c_master_recv(client, buf, sizeof(buf));
  63         if (err == sizeof(buf))
  64                 return buf[3] << 8;
  65         return 0;
  66 }
  67 
  68 static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
  69 {
  70         if (v->index > 0)
  71                 return -EINVAL;
  72 
  73         /* only support FM for now */
  74         strscpy(v->name, "FM", sizeof(v->name));
  75         v->type = V4L2_TUNER_RADIO;
  76         v->rangelow = TEF6862_LO_FREQ;
  77         v->rangehigh = TEF6862_HI_FREQ;
  78         v->rxsubchans = V4L2_TUNER_SUB_MONO;
  79         v->capability = V4L2_TUNER_CAP_LOW;
  80         v->audmode = V4L2_TUNER_MODE_STEREO;
  81         v->signal = tef6862_sigstr(v4l2_get_subdevdata(sd));
  82 
  83         return 0;
  84 }
  85 
  86 static int tef6862_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v)
  87 {
  88         return v->index ? -EINVAL : 0;
  89 }
  90 
  91 static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f)
  92 {
  93         struct tef6862_state *state = to_state(sd);
  94         struct i2c_client *client = v4l2_get_subdevdata(sd);
  95         unsigned freq = f->frequency;
  96         u16 pll;
  97         u8 i2cmsg[3];
  98         int err;
  99 
 100         if (f->tuner != 0)
 101                 return -EINVAL;
 102 
 103         freq = clamp(freq, TEF6862_LO_FREQ, TEF6862_HI_FREQ);
 104         pll = 1964 + ((freq - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
 105         i2cmsg[0] = (MSA_MODE_PRESET << MSA_MODE_SHIFT) | WM_SUB_PLLM;
 106         i2cmsg[1] = (pll >> 8) & 0xff;
 107         i2cmsg[2] = pll & 0xff;
 108 
 109         err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg));
 110         if (err != sizeof(i2cmsg))
 111                 return err < 0 ? err : -EIO;
 112 
 113         state->freq = freq;
 114         return 0;
 115 }
 116 
 117 static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
 118 {
 119         struct tef6862_state *state = to_state(sd);
 120 
 121         if (f->tuner != 0)
 122                 return -EINVAL;
 123         f->type = V4L2_TUNER_RADIO;
 124         f->frequency = state->freq;
 125         return 0;
 126 }
 127 
 128 static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = {
 129         .g_tuner = tef6862_g_tuner,
 130         .s_tuner = tef6862_s_tuner,
 131         .s_frequency = tef6862_s_frequency,
 132         .g_frequency = tef6862_g_frequency,
 133 };
 134 
 135 static const struct v4l2_subdev_ops tef6862_ops = {
 136         .tuner = &tef6862_tuner_ops,
 137 };
 138 
 139 /*
 140  * Generic i2c probe
 141  * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
 142  */
 143 
 144 static int tef6862_probe(struct i2c_client *client,
 145                          const struct i2c_device_id *id)
 146 {
 147         struct tef6862_state *state;
 148         struct v4l2_subdev *sd;
 149 
 150         /* Check if the adapter supports the needed features */
 151         if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 152                 return -EIO;
 153 
 154         v4l_info(client, "chip found @ 0x%02x (%s)\n",
 155                         client->addr << 1, client->adapter->name);
 156 
 157         state = kzalloc(sizeof(struct tef6862_state), GFP_KERNEL);
 158         if (state == NULL)
 159                 return -ENOMEM;
 160         state->freq = TEF6862_LO_FREQ;
 161 
 162         sd = &state->sd;
 163         v4l2_i2c_subdev_init(sd, client, &tef6862_ops);
 164 
 165         return 0;
 166 }
 167 
 168 static int tef6862_remove(struct i2c_client *client)
 169 {
 170         struct v4l2_subdev *sd = i2c_get_clientdata(client);
 171 
 172         v4l2_device_unregister_subdev(sd);
 173         kfree(to_state(sd));
 174         return 0;
 175 }
 176 
 177 static const struct i2c_device_id tef6862_id[] = {
 178         {DRIVER_NAME, 0},
 179         {},
 180 };
 181 
 182 MODULE_DEVICE_TABLE(i2c, tef6862_id);
 183 
 184 static struct i2c_driver tef6862_driver = {
 185         .driver = {
 186                 .name   = DRIVER_NAME,
 187         },
 188         .probe          = tef6862_probe,
 189         .remove         = tef6862_remove,
 190         .id_table       = tef6862_id,
 191 };
 192 
 193 module_i2c_driver(tef6862_driver);
 194 
 195 MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner");
 196 MODULE_AUTHOR("Mocean Laboratories");
 197 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */