0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/usb.h>
0011 #include <linux/init.h>
0012 #include <linux/slab.h>
0013 #include <linux/input.h>
0014 #include <linux/mutex.h>
0015 #include <linux/i2c.h>
0016
0017 #include <linux/videodev2.h>
0018 #include <media/v4l2-common.h>
0019 #include <media/v4l2-device.h>
0020 #include <media/v4l2-ioctl.h>
0021 #include <media/v4l2-event.h>
0022 #include <linux/platform_data/media/si4713.h>
0023
0024 #include "si4713.h"
0025
0026
0027 MODULE_AUTHOR("Dinesh Ram <dinesh.ram@cern.ch>");
0028 MODULE_DESCRIPTION("Si4713 FM Transmitter USB driver");
0029 MODULE_LICENSE("GPL v2");
0030
0031
0032 #define USB_SI4713_VENDOR 0x10c4
0033 #define USB_SI4713_PRODUCT 0x8244
0034
0035 #define BUFFER_LENGTH 64
0036 #define USB_TIMEOUT 1000
0037 #define USB_RESP_TIMEOUT 50000
0038
0039
0040 static const struct usb_device_id usb_si4713_usb_device_table[] = {
0041 {USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT,
0042 USB_CLASS_HID, 0, 0) },
0043 { }
0044 };
0045
0046 MODULE_DEVICE_TABLE(usb, usb_si4713_usb_device_table);
0047
0048 struct si4713_usb_device {
0049 struct usb_device *usbdev;
0050 struct usb_interface *intf;
0051 struct video_device vdev;
0052 struct v4l2_device v4l2_dev;
0053 struct v4l2_subdev *v4l2_subdev;
0054 struct mutex lock;
0055 struct i2c_adapter i2c_adapter;
0056
0057 u8 *buffer;
0058 };
0059
0060 static inline struct si4713_usb_device *to_si4713_dev(struct v4l2_device *v4l2_dev)
0061 {
0062 return container_of(v4l2_dev, struct si4713_usb_device, v4l2_dev);
0063 }
0064
0065 static int vidioc_querycap(struct file *file, void *priv,
0066 struct v4l2_capability *v)
0067 {
0068 struct si4713_usb_device *radio = video_drvdata(file);
0069
0070 strscpy(v->driver, "radio-usb-si4713", sizeof(v->driver));
0071 strscpy(v->card, "Si4713 FM Transmitter", sizeof(v->card));
0072 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
0073 return 0;
0074 }
0075
0076 static int vidioc_g_modulator(struct file *file, void *priv,
0077 struct v4l2_modulator *vm)
0078 {
0079 struct si4713_usb_device *radio = video_drvdata(file);
0080
0081 return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_modulator, vm);
0082 }
0083
0084 static int vidioc_s_modulator(struct file *file, void *priv,
0085 const struct v4l2_modulator *vm)
0086 {
0087 struct si4713_usb_device *radio = video_drvdata(file);
0088
0089 return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_modulator, vm);
0090 }
0091
0092 static int vidioc_s_frequency(struct file *file, void *priv,
0093 const struct v4l2_frequency *vf)
0094 {
0095 struct si4713_usb_device *radio = video_drvdata(file);
0096
0097 return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_frequency, vf);
0098 }
0099
0100 static int vidioc_g_frequency(struct file *file, void *priv,
0101 struct v4l2_frequency *vf)
0102 {
0103 struct si4713_usb_device *radio = video_drvdata(file);
0104
0105 return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_frequency, vf);
0106 }
0107
0108 static const struct v4l2_ioctl_ops usb_si4713_ioctl_ops = {
0109 .vidioc_querycap = vidioc_querycap,
0110 .vidioc_g_modulator = vidioc_g_modulator,
0111 .vidioc_s_modulator = vidioc_s_modulator,
0112 .vidioc_g_frequency = vidioc_g_frequency,
0113 .vidioc_s_frequency = vidioc_s_frequency,
0114 .vidioc_log_status = v4l2_ctrl_log_status,
0115 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
0116 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
0117 };
0118
0119
0120 static const struct v4l2_file_operations usb_si4713_fops = {
0121 .owner = THIS_MODULE,
0122 .open = v4l2_fh_open,
0123 .release = v4l2_fh_release,
0124 .poll = v4l2_ctrl_poll,
0125 .unlocked_ioctl = video_ioctl2,
0126 };
0127
0128 static void usb_si4713_video_device_release(struct v4l2_device *v4l2_dev)
0129 {
0130 struct si4713_usb_device *radio = to_si4713_dev(v4l2_dev);
0131 struct i2c_adapter *adapter = &radio->i2c_adapter;
0132
0133 i2c_del_adapter(adapter);
0134 v4l2_device_unregister(&radio->v4l2_dev);
0135 kfree(radio->buffer);
0136 kfree(radio);
0137 }
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152 static int si4713_send_startup_command(struct si4713_usb_device *radio)
0153 {
0154 unsigned long until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1;
0155 u8 *buffer = radio->buffer;
0156 int retval;
0157
0158
0159 retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
0160 0x09, 0x21, 0x033f, 0, radio->buffer,
0161 BUFFER_LENGTH, USB_TIMEOUT);
0162 if (retval < 0)
0163 return retval;
0164
0165 for (;;) {
0166
0167 retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
0168 0x01, 0xa1, 0x033f, 0, radio->buffer,
0169 BUFFER_LENGTH, USB_TIMEOUT);
0170 if (retval < 0)
0171 return retval;
0172 if (!radio->buffer[1]) {
0173
0174
0175 switch (buffer[1]) {
0176 case 0x32:
0177 if (radio->buffer[2] == 0)
0178 return 0;
0179 break;
0180 case 0x14:
0181 case 0x12:
0182 if (radio->buffer[2] & SI4713_CTS)
0183 return 0;
0184 break;
0185 case 0x06:
0186 if ((radio->buffer[2] & SI4713_CTS) && radio->buffer[9] == 0x08)
0187 return 0;
0188 break;
0189 default:
0190 return 0;
0191 }
0192 }
0193 if (time_is_before_jiffies(until_jiffies))
0194 return -EIO;
0195 msleep(3);
0196 }
0197
0198 return retval;
0199 }
0200
0201 struct si4713_start_seq_table {
0202 int len;
0203 u8 payload[8];
0204 };
0205
0206
0207
0208
0209
0210
0211 static const struct si4713_start_seq_table start_seq[] = {
0212
0213 { 1, { 0x03 } },
0214 { 2, { 0x32, 0x7f } },
0215 { 6, { 0x06, 0x03, 0x03, 0x08, 0x01, 0x0f } },
0216 { 2, { 0x14, 0x02 } },
0217 { 2, { 0x09, 0x90 } },
0218 { 3, { 0x08, 0x90, 0xfa } },
0219 { 2, { 0x36, 0x01 } },
0220 { 2, { 0x05, 0x03 } },
0221 { 7, { 0x06, 0x00, 0x06, 0x0e, 0x01, 0x0f, 0x05 } },
0222 { 1, { 0x12 } },
0223
0224
0225 { 1, { 0x03 } },
0226 { 1, { 0x01 } },
0227 { 2, { 0x09, 0x90 } },
0228 { 3, { 0x08, 0x90, 0xfa } },
0229 { 1, { 0x34 } },
0230 { 2, { 0x35, 0x01 } },
0231 { 2, { 0x36, 0x01 } },
0232 { 2, { 0x30, 0x09 } },
0233 { 4, { 0x30, 0x06, 0x00, 0xe2 } },
0234 { 3, { 0x31, 0x01, 0x30 } },
0235 { 3, { 0x31, 0x04, 0x09 } },
0236 { 2, { 0x05, 0x02 } },
0237 { 6, { 0x06, 0x03, 0x03, 0x08, 0x01, 0x0f } },
0238 };
0239
0240 static int si4713_start_seq(struct si4713_usb_device *radio)
0241 {
0242 int retval = 0;
0243 int i;
0244
0245 radio->buffer[0] = 0x3f;
0246
0247 for (i = 0; i < ARRAY_SIZE(start_seq); i++) {
0248 int len = start_seq[i].len;
0249 const u8 *payload = start_seq[i].payload;
0250
0251 memcpy(radio->buffer + 1, payload, len);
0252 memset(radio->buffer + len + 1, 0, BUFFER_LENGTH - 1 - len);
0253 retval = si4713_send_startup_command(radio);
0254 }
0255
0256 return retval;
0257 }
0258
0259 static struct i2c_board_info si4713_board_info = {
0260 I2C_BOARD_INFO("si4713", SI4713_I2C_ADDR_BUSEN_HIGH),
0261 };
0262
0263 struct si4713_command_table {
0264 int command_id;
0265 u8 payload[8];
0266 };
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276 static struct si4713_command_table command_table[] = {
0277
0278 { SI4713_CMD_POWER_UP, { 0x00, SI4713_PWUP_NARGS + 1, SI4713_PWUP_NRESP} },
0279 { SI4713_CMD_GET_REV, { 0x03, 0x01, SI4713_GETREV_NRESP } },
0280 { SI4713_CMD_POWER_DOWN, { 0x00, 0x01, SI4713_PWDN_NRESP} },
0281 { SI4713_CMD_SET_PROPERTY, { 0x00, SI4713_SET_PROP_NARGS + 1, SI4713_SET_PROP_NRESP } },
0282 { SI4713_CMD_GET_PROPERTY, { 0x00, SI4713_GET_PROP_NARGS + 1, SI4713_GET_PROP_NRESP } },
0283 { SI4713_CMD_TX_TUNE_FREQ, { 0x03, SI4713_TXFREQ_NARGS + 1, SI4713_TXFREQ_NRESP } },
0284 { SI4713_CMD_TX_TUNE_POWER, { 0x03, SI4713_TXPWR_NARGS + 1, SI4713_TXPWR_NRESP } },
0285 { SI4713_CMD_TX_TUNE_MEASURE, { 0x03, SI4713_TXMEA_NARGS + 1, SI4713_TXMEA_NRESP } },
0286 { SI4713_CMD_TX_TUNE_STATUS, { 0x00, SI4713_TXSTATUS_NARGS + 1, SI4713_TXSTATUS_NRESP } },
0287 { SI4713_CMD_TX_ASQ_STATUS, { 0x03, SI4713_ASQSTATUS_NARGS + 1, SI4713_ASQSTATUS_NRESP } },
0288 { SI4713_CMD_GET_INT_STATUS, { 0x03, 0x01, SI4713_GET_STATUS_NRESP } },
0289 { SI4713_CMD_TX_RDS_BUFF, { 0x03, SI4713_RDSBUFF_NARGS + 1, SI4713_RDSBUFF_NRESP } },
0290 { SI4713_CMD_TX_RDS_PS, { 0x00, SI4713_RDSPS_NARGS + 1, SI4713_RDSPS_NRESP } },
0291 };
0292
0293 static int send_command(struct si4713_usb_device *radio, u8 *payload, char *data, int len)
0294 {
0295 int retval;
0296
0297 radio->buffer[0] = 0x3f;
0298 radio->buffer[1] = 0x06;
0299
0300 memcpy(radio->buffer + 2, payload, 3);
0301 memcpy(radio->buffer + 5, data, len);
0302 memset(radio->buffer + 5 + len, 0, BUFFER_LENGTH - 5 - len);
0303
0304
0305 retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
0306 0x09, 0x21, 0x033f, 0, radio->buffer,
0307 BUFFER_LENGTH, USB_TIMEOUT);
0308
0309 return retval < 0 ? retval : 0;
0310 }
0311
0312 static int si4713_i2c_read(struct si4713_usb_device *radio, char *data, int len)
0313 {
0314 unsigned long until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1;
0315 int retval;
0316
0317
0318 for (;;) {
0319 retval = usb_control_msg(radio->usbdev,
0320 usb_rcvctrlpipe(radio->usbdev, 0),
0321 0x01, 0xa1, 0x033f, 0, radio->buffer,
0322 BUFFER_LENGTH, USB_TIMEOUT);
0323 if (retval < 0)
0324 return retval;
0325
0326
0327
0328
0329
0330
0331
0332
0333 if (radio->buffer[1] == 0 && (radio->buffer[2] & SI4713_CTS)) {
0334 memcpy(data, radio->buffer + 2, len);
0335 return 0;
0336 }
0337 if (time_is_before_jiffies(until_jiffies)) {
0338
0339 data[0] = 0;
0340 return 0;
0341 }
0342 msleep(3);
0343 }
0344 }
0345
0346 static int si4713_i2c_write(struct si4713_usb_device *radio, char *data, int len)
0347 {
0348 int retval = -EINVAL;
0349 int i;
0350
0351 if (len > BUFFER_LENGTH - 5)
0352 return -EINVAL;
0353
0354 for (i = 0; i < ARRAY_SIZE(command_table); i++) {
0355 if (data[0] == command_table[i].command_id)
0356 retval = send_command(radio, command_table[i].payload,
0357 data, len);
0358 }
0359
0360 return retval < 0 ? retval : 0;
0361 }
0362
0363 static int si4713_transfer(struct i2c_adapter *i2c_adapter,
0364 struct i2c_msg *msgs, int num)
0365 {
0366 struct si4713_usb_device *radio = i2c_get_adapdata(i2c_adapter);
0367 int retval = -EINVAL;
0368 int i;
0369
0370 for (i = 0; i < num; i++) {
0371 if (msgs[i].flags & I2C_M_RD)
0372 retval = si4713_i2c_read(radio, msgs[i].buf, msgs[i].len);
0373 else
0374 retval = si4713_i2c_write(radio, msgs[i].buf, msgs[i].len);
0375 if (retval)
0376 break;
0377 }
0378
0379 return retval ? retval : num;
0380 }
0381
0382 static u32 si4713_functionality(struct i2c_adapter *adapter)
0383 {
0384 return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
0385 }
0386
0387 static const struct i2c_algorithm si4713_algo = {
0388 .master_xfer = si4713_transfer,
0389 .functionality = si4713_functionality,
0390 };
0391
0392
0393
0394 static const struct i2c_adapter si4713_i2c_adapter_template = {
0395 .name = "si4713-i2c",
0396 .owner = THIS_MODULE,
0397 .algo = &si4713_algo,
0398 };
0399
0400 static int si4713_register_i2c_adapter(struct si4713_usb_device *radio)
0401 {
0402 radio->i2c_adapter = si4713_i2c_adapter_template;
0403
0404 radio->i2c_adapter.dev.parent = &radio->usbdev->dev;
0405 i2c_set_adapdata(&radio->i2c_adapter, radio);
0406
0407 return i2c_add_adapter(&radio->i2c_adapter);
0408 }
0409
0410
0411 static int usb_si4713_probe(struct usb_interface *intf,
0412 const struct usb_device_id *id)
0413 {
0414 struct si4713_usb_device *radio;
0415 struct i2c_adapter *adapter;
0416 struct v4l2_subdev *sd;
0417 int retval;
0418
0419 dev_info(&intf->dev, "Si4713 development board discovered: (%04X:%04X)\n",
0420 id->idVendor, id->idProduct);
0421
0422
0423 radio = kzalloc(sizeof(struct si4713_usb_device), GFP_KERNEL);
0424 if (radio)
0425 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
0426
0427 if (!radio || !radio->buffer) {
0428 dev_err(&intf->dev, "kmalloc for si4713_usb_device failed\n");
0429 kfree(radio);
0430 return -ENOMEM;
0431 }
0432
0433 mutex_init(&radio->lock);
0434
0435 radio->usbdev = interface_to_usbdev(intf);
0436 radio->intf = intf;
0437 usb_set_intfdata(intf, &radio->v4l2_dev);
0438
0439 retval = si4713_start_seq(radio);
0440 if (retval < 0)
0441 goto err_v4l2;
0442
0443 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
0444 if (retval < 0) {
0445 dev_err(&intf->dev, "couldn't register v4l2_device\n");
0446 goto err_v4l2;
0447 }
0448
0449 retval = si4713_register_i2c_adapter(radio);
0450 if (retval < 0) {
0451 dev_err(&intf->dev, "could not register i2c device\n");
0452 goto err_i2cdev;
0453 }
0454
0455 adapter = &radio->i2c_adapter;
0456 sd = v4l2_i2c_new_subdev_board(&radio->v4l2_dev, adapter,
0457 &si4713_board_info, NULL);
0458 radio->v4l2_subdev = sd;
0459 if (!sd) {
0460 dev_err(&intf->dev, "cannot get v4l2 subdevice\n");
0461 retval = -ENODEV;
0462 goto del_adapter;
0463 }
0464
0465 radio->vdev.ctrl_handler = sd->ctrl_handler;
0466 radio->v4l2_dev.release = usb_si4713_video_device_release;
0467 strscpy(radio->vdev.name, radio->v4l2_dev.name,
0468 sizeof(radio->vdev.name));
0469 radio->vdev.v4l2_dev = &radio->v4l2_dev;
0470 radio->vdev.fops = &usb_si4713_fops;
0471 radio->vdev.ioctl_ops = &usb_si4713_ioctl_ops;
0472 radio->vdev.lock = &radio->lock;
0473 radio->vdev.release = video_device_release_empty;
0474 radio->vdev.vfl_dir = VFL_DIR_TX;
0475 radio->vdev.device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
0476
0477 video_set_drvdata(&radio->vdev, radio);
0478
0479 retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
0480 if (retval < 0) {
0481 dev_err(&intf->dev, "could not register video device\n");
0482 goto del_adapter;
0483 }
0484
0485 dev_info(&intf->dev, "V4L2 device registered as %s\n",
0486 video_device_node_name(&radio->vdev));
0487
0488 return 0;
0489
0490 del_adapter:
0491 i2c_del_adapter(adapter);
0492 err_i2cdev:
0493 v4l2_device_unregister(&radio->v4l2_dev);
0494 err_v4l2:
0495 kfree(radio->buffer);
0496 kfree(radio);
0497 return retval;
0498 }
0499
0500 static void usb_si4713_disconnect(struct usb_interface *intf)
0501 {
0502 struct si4713_usb_device *radio = to_si4713_dev(usb_get_intfdata(intf));
0503
0504 dev_info(&intf->dev, "Si4713 development board now disconnected\n");
0505
0506 mutex_lock(&radio->lock);
0507 usb_set_intfdata(intf, NULL);
0508 video_unregister_device(&radio->vdev);
0509 v4l2_device_disconnect(&radio->v4l2_dev);
0510 mutex_unlock(&radio->lock);
0511 v4l2_device_put(&radio->v4l2_dev);
0512 }
0513
0514
0515 static struct usb_driver usb_si4713_driver = {
0516 .name = "radio-usb-si4713",
0517 .probe = usb_si4713_probe,
0518 .disconnect = usb_si4713_disconnect,
0519 .id_table = usb_si4713_usb_device_table,
0520 };
0521
0522 module_usb_driver(usb_si4713_driver);