Re: Logilink VG0022A firmware/si2157 probe
On 10/17/19 4:46 PM, JP wrote: Hi there, On 10/17/19 2:15 PM, Antti Palosaari wrote: Hello, On 10/17/19 12:08 PM, Sean Young wrote: Hi Antti, I have a Logilink VG0022A device which is an af9035.c type device (with ITE 9xxx frontned). The probe of the si2146 tuner fails and returns 0xffs. Now I would like to work on fixing this. Mauro suggested the firmware might be incorrect. Any tips on extracting the firmware? I can try and dump usb traffic from Windows and see what firmware is being used there. How did you extract the firmware? If the receiver has onboard firmware, isn't that the right one? Then the windows driver has no need to load one. Or am I missing the point here? Actually I am not even 100% sure what are used chips of that device, but I expect those are: usb-interface: IT9303, needs firmware, cannot be loaded from the eeprom IIRC demodulator: Si2168 (revision B or C?), chip has rom that contains firmware, but usually it is replaced newer by downloading tuner: Si2157 or same family, similar firmware solution than Si2168. Si2157 I originally used didn't uploaded firmware update at all, later there was added more and more Silabs tuner versions and firmware downloading. Si2168B could be started (and it worked at the time I tested) with default rom firmware by using that kind of stub firmware: $ hexdump -C dvb-demod-si2168-b40-01.fw 05 00 00 00 00 00 00 00 || 0008 Not sure if that works any other than just Si2168B. Any other suggestions for this device? You might be able to save me a lot of time since you have experience with these types of devices, I do not. Extracting firmware is done almost always by following steps: 1) take sniffs from the some bus (usb/i2c) 2) identify firmware download section, detect it starting point and ending point ~few first and last bytes 3) find that firmware binary located inside of binary driver * grep, hexeditor, etc * example LANG=C grep -obUaP "\x08\x05\x00" driver.sys 4) use dd command to copy firmware blob from binary driver to separate file (you need to know firmware location and length inside binary) It is also possible to dump firmware to file from bus sniffs too, but it requires writing some simple script. Dumping it from the binary driver is usually still most easiest way. At some point I downloaded bunch of drivers to find out multiple firmware versions for si2168 and made simple script to ease things. Script is attached. After all, I suspect root of issue may be still be buggy i2c... Me too. Jan Pieter. It could be interesting to see from the sniffs what kind of firmwares windows driver downloads to different chips AND if i2c communication is working properly. regards Antti -- http://palosaari.fi/
Re: Logilink VG0022A firmware/si2157 probe
Hello, On 10/17/19 12:08 PM, Sean Young wrote: Hi Antti, I have a Logilink VG0022A device which is an af9035.c type device (with ITE 9xxx frontned). The probe of the si2146 tuner fails and returns 0xffs. Now I would like to work on fixing this. Mauro suggested the firmware might be incorrect. Any tips on extracting the firmware? I can try and dump usb traffic from Windows and see what firmware is being used there. How did you extract the firmware? Any other suggestions for this device? You might be able to save me a lot of time since you have experience with these types of devices, I do not. Extracting firmware is done almost always by following steps: 1) take sniffs from the some bus (usb/i2c) 2) identify firmware download section, detect it starting point and ending point ~few first and last bytes 3) find that firmware binary located inside of binary driver * grep, hexeditor, etc * example LANG=C grep -obUaP "\x08\x05\x00" driver.sys 4) use dd command to copy firmware blob from binary driver to separate file (you need to know firmware location and length inside binary) It is also possible to dump firmware to file from bus sniffs too, but it requires writing some simple script. Dumping it from the binary driver is usually still most easiest way. At some point I downloaded bunch of drivers to find out multiple firmware versions for si2168 and made simple script to ease things. Script is attached. After all, I suspect root of issue may be still be buggy i2c... regards Antti -- http://palosaari.fi/ #!/usr/bin/env python # Silicon Labs Si2168 firmware extractor. # Copyright (C) 2015 Antti Palosaari # Usage: si2168_extract_firmware.py binary_driver_name.sys import sys import struct import md5 fread = file(sys.argv[1], 'rb') binary = fread.read() offset = 0 # Known firmware md5 and its version fw_ver_tab = { '02c9b1e751f362621c649ea831410b61' : '4.0.7', 'b2670d8ae5e3369fc71edbb98cdd8f6e' : '4.0.11', '8dfc2483d90282bbb05817fbbc282376' : '4.0.19', 'c8e089c351e9834060e962356f8697b8' : '4.0.25', } while True: # Match 17-byte firmware header # 04 01 00 00 00 00 9a 41 05 1b af 33 02 1b 3e 7d 2a | A20 (not supported) # 08 05 00 xx xx xx xx xx xx 00 00 00 00 00 00 00 00 | B40 offset = binary.find('\x08\x05\x00', offset) if offset == -1: print "Done" break if (binary[offset + 9:offset + 17] != '\x00\x00\x00\x00\x00\x00\x00\x00'): offset = offset + 1 continue print "Possible 17-byte Si2168-B40 firmware header found at 0x%x" % (offset) fw_filename = 'dvb-demod-si2168-b40-01.fw_' + str(offset) fw_write = open(fw_filename, 'wb') fw_md5 = md5.new() while True: fields = struct.unpack("B", binary[offset]) fw_data_len = fields[0] # Firmware chunk first byte tells bytes to upload - 16 is max if fw_data_len == 0 or fw_data_len > 16: break # Check remaining (unused) bytes on firmware 17-byte chunk are all zero data_valid = True for x in range(offset + fw_data_len + 1, offset + 17): if (binary[x] != '\x00'): data_valid = False break if data_valid == False: break # Firmware chunk validated, write it to file fw_write.write(binary[offset + 0:offset + 17]) fw_md5.update(binary[offset + 0:offset + 17]) offset = offset + 17 fw_write.close() if fw_md5.hexdigest() in fw_ver_tab: fw_ver = fw_ver_tab[fw_md5.hexdigest()] else: fw_ver = '' print "Firmware md5 '%s'" % (fw_md5.hexdigest()) print "Firmware version '%s'" % (fw_ver) print "Firmware stored to file '%s'" % (fw_filename) offset = offset + 1 fread.close()
Re: [PATCH] gl861: re-implement i2c adapter logic
On 8/24/19 2:33 AM, Antti Palosaari wrote: On 8/23/19 8:28 PM, Akihiro TSUKADA wrote: Hi, thanks for the example patch. Here is debug log I tested multibyte i2c writes using zl10353 demod. All returned bytes are not same, but it due to write only register bits I think. dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 03 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 44 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< 46 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 15 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 0f dvb_usb_gl861 1-13:1.0: 5 | 40 03 00 1e 50 00 05 00 >>> 0c 77 aa bb cc dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 0c dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 77 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< aa dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 3b dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 4c Now if you look your tuner i2c implementation... buf[0] = msg->addr << 1; memcpy(buf + 1, msg->buf, msg->len); ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), GL861_REQ_I2C_RAW, GL861_WRITE, priv->i2c_client_demod->addr << (8 + 1), 0xFE, buf, msg->len + 1, 2000); ...it translates same. Log of an 1-byte read from tuner in Friio looks like the following: (re-formatted from my past post: https://patchwork.linuxtv.org/comment/92946/ ) 40 03 00 30 fe 00 01 00 >>> c1 # command a read from the tuner@0x60 (hence 0xc1) c0 02 00 30 00 01 01 00 <<< 7c # get the result (return value: 0x7c) so, - One read is composed of *two* USB messages. (note that friio_tuner_i2c_xfer() does NOT combine the two I2C messages of one read, and issues separate USB message for each, contrary to gl861_i2c_master_xfer()). - The second USB message uses CMD_READ but 'index'(demod register addr) value exceeds 8bit (0x0100), thus cannot use the normal gl861_i2c_master_xfer() as is. It looks to me different. It looks just read command done with 2 separate I2C messages (look I2C specs REPEATED START vs. STOP START). OK, I will add support for bulk I2C READs for adapter too, no problem. See updated patch on ml. Tested it quickly against qt1010 tuner and results are expected: dvb_usb_gl861 1-14:1.0: 0 | 40 01 1a 1e 62 00 00 00 >>> dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 29 00 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 0 | 40 03 00 c4 29 00 00 00 >>> dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 00 01 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 00 01 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 00 01 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 1 | c0 02 00 c4 00 01 01 00 <<< 39 dvb_usb_gl861 1-14:1.0: 0 | 40 01 0a 1e 62 00 00 00 >>> Register 29 is likely chip id and its value is always 39. So it first makes normal write+write to that register which sets and leaves chip registers address counter to that. After that each plain I2C read request gives 39 which is correct content for that register. Antti -- http://palosaari.fi/
[PATCH v2] gl861: re-implement I2C adapter logic
Device I2C adapter is capable of writing and reading large messages. For I2C writes there is 2 methods: simple for max 2 byte messages and usb_control_msg() with payload data for larger I2C messages. Add I2C adapter logic which selects suitable method according to message size. Add also support for plain I2C read. Cc: Akihiro TSUKADA Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/gl861.c | 216 --- 1 file changed, 159 insertions(+), 57 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c index b784d9da1a82..ead6268af7ad 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -14,6 +14,154 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +struct gl861 { + /* USB control message buffer */ + u8 buf[16]; + + struct i2c_adapter *demod_sub_i2c; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; + struct i2c_adapter tuner_adap; +}; + +#define CMD_WRITE_SHORT 0x01 +#define CMD_READ0x02 +#define CMD_WRITE 0x03 + +static int gl861_ctrl_msg(struct dvb_usb_device *d, u8 request, u16 value, + u16 index, void *data, u16 size) +{ + struct gl861 *ctx = d_to_priv(d); + struct usb_interface *intf = d->intf; + int ret; + unsigned int pipe; + u8 requesttype; + + mutex_lock(&d->usb_mutex); + + switch (request) { + case CMD_WRITE: + memcpy(ctx->buf, data, size); + /* Fall through */ + case CMD_WRITE_SHORT: + pipe = usb_sndctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_OUT; + break; + case CMD_READ: + pipe = usb_rcvctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_IN; + break; + default: + ret = -EINVAL; + goto err_mutex_unlock; + } + + ret = usb_control_msg(d->udev, pipe, request, requesttype, value, + index, ctx->buf, size, 200); + dev_dbg(&intf->dev, "%d | %02x %02x %*ph %*ph %*ph %s %*ph\n", + ret, requesttype, request, 2, &value, 2, &index, 2, &size, + (requesttype & USB_DIR_IN) ? "<<<" : ">>>", size, ctx->buf); + if (ret < 0) + goto err_mutex_unlock; + + if (request == CMD_READ) + memcpy(data, ctx->buf, size); + + usleep_range(1000, 2000); /* Avoid I2C errors */ + + mutex_unlock(&d->usb_mutex); + + return 0; + +err_mutex_unlock: + mutex_unlock(&d->usb_mutex); + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int gl861_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], +int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct usb_interface *intf = d->intf; + struct gl861 *ctx = d_to_priv(d); + int ret; + u8 request, *data; + u16 value, index, size; + + /* XXX: I2C adapter maximum data lengths are not tested */ + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + /* I2C write */ + if (msg[0].len < 2 || msg[0].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + + if (msg[0].len == 2) { + request = CMD_WRITE_SHORT; + value |= msg[0].buf[1]; + size = 0; + data = NULL; + } else { + request = CMD_WRITE; + size = msg[0].len - 1; + data = &msg[0].buf[1]; + } + + ret = gl861_ctrl_msg(d, request, value, index, data, size); + } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + /* I2C write + read */ + if (msg[0].len > 1 || msg[1].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + request = CMD_READ; + + ret = gl861_ctrl_msg(d, request, value, index, +msg[1].buf, msg[1].len); + } else if (num == 1 && (msg[0].flags & I2C_M_RD)) { + /* I2C read */ + if (msg[0].len > sizeof(ctx->buf)) { + ret =
Re: [PATCH] gl861: re-implement i2c adapter logic
On 8/23/19 8:28 PM, Akihiro TSUKADA wrote: Hi, thanks for the example patch. Here is debug log I tested multibyte i2c writes using zl10353 demod. All returned bytes are not same, but it due to write only register bits I think. dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 03 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 44 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< 46 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 15 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 0f dvb_usb_gl861 1-13:1.0: 5 | 40 03 00 1e 50 00 05 00 >>> 0c 77 aa bb cc dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 0c dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 77 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< aa dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 3b dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 4c Now if you look your tuner i2c implementation... buf[0] = msg->addr << 1; memcpy(buf + 1, msg->buf, msg->len); ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), GL861_REQ_I2C_RAW, GL861_WRITE, priv->i2c_client_demod->addr << (8 + 1), 0xFE, buf, msg->len + 1, 2000); ...it translates same. Log of an 1-byte read from tuner in Friio looks like the following: (re-formatted from my past post: https://patchwork.linuxtv.org/comment/92946/ ) 40 03 00 30 fe 00 01 00 >>> c1 # command a read from the tuner@0x60 (hence 0xc1) c0 02 00 30 00 01 01 00 <<< 7c # get the result (return value: 0x7c) so, - One read is composed of *two* USB messages. (note that friio_tuner_i2c_xfer() does NOT combine the two I2C messages of one read, and issues separate USB message for each, contrary to gl861_i2c_master_xfer()). - The second USB message uses CMD_READ but 'index'(demod register addr) value exceeds 8bit (0x0100), thus cannot use the normal gl861_i2c_master_xfer() as is. It looks to me different. It looks just read command done with 2 separate I2C messages (look I2C specs REPEATED START vs. STOP START). OK, I will add support for bulk I2C READs for adapter too, no problem. Antti -- http://palosaari.fi/
Re: [PATCH] gl861: re-implement i2c adapter logic
On 8/22/19 8:34 AM, Antti Palosaari wrote: Device I2C adapter is capable of writing and reading large messages. For I2C writes there is 2 methods: simple for max 2 byte messages and usb_control_msg() with payload data for larger I2C messages. Add I2C adapter logic which selects suitable method according to message size. Here is debug log I tested multibyte i2c writes using zl10353 demod. All returned bytes are not same, but it due to write only register bits I think. dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 03 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 44 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< 46 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 15 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 0f dvb_usb_gl861 1-13:1.0: 5 | 40 03 00 1e 50 00 05 00 >>> 0c 77 aa bb cc dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 50 00 01 00 <<< 0c dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 51 00 01 00 <<< 77 dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 52 00 01 00 <<< aa dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 53 00 01 00 <<< 3b dvb_usb_gl861 1-13:1.0: 1 | c0 02 00 1e 54 00 01 00 <<< 4c Now if you look your tuner i2c implementation... buf[0] = msg->addr << 1; memcpy(buf + 1, msg->buf, msg->len); ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), GL861_REQ_I2C_RAW, GL861_WRITE, priv->i2c_client_demod->addr << (8 + 1), 0xFE, buf, msg->len + 1, 2000); ...it translates same. It writes i2c message to demod which; byte0 0xfe, demod register/cmd/mailbox for tuner i2c bus byte1 tuner i2c address byte2-n tuner i2c data Antti -- http://palosaari.fi/
[PATCH] gl861: re-implement i2c adapter logic
Device I2C adapter is capable of writing and reading large messages. For I2C writes there is 2 methods: simple for max 2 byte messages and usb_control_msg() with payload data for larger I2C messages. Add I2C adapter logic which selects suitable method according to message size. Cc: Akihiro TSUKADA Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/gl861.c | 206 +++ 1 file changed, 149 insertions(+), 57 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c index b784d9da1a82..b8358cd2e4b7 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -14,6 +14,144 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); +struct gl861 { + /* USB control message buffer */ + u8 buf[16]; + + struct i2c_adapter *demod_sub_i2c; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; + struct i2c_adapter tuner_adap; +}; + +#define CMD_WRITE_SHORT 0x01 +#define CMD_READ0x02 +#define CMD_WRITE 0x03 + +static int gl861_ctrl_msg(struct dvb_usb_device *d, u8 request, u16 value, + u16 index, void *data, u16 size) +{ + struct gl861 *ctx = d_to_priv(d); + struct usb_interface *intf = d->intf; + int ret; + unsigned int pipe; + u8 requesttype; + + mutex_lock(&d->usb_mutex); + + switch (request) { + case CMD_WRITE_SHORT: + pipe = usb_sndctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_OUT; + break; + case CMD_READ: + pipe = usb_rcvctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_IN; + break; + case CMD_WRITE: + pipe = usb_sndctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_OUT; + memcpy(ctx->buf, data, size); + break; + default: + ret = -EINVAL; + goto err_mutex_unlock; + } + + ret = usb_control_msg(d->udev, pipe, request, requesttype, value, + index, ctx->buf, size, 200); + dev_dbg(&intf->dev, "%d | %02x %02x %*ph %*ph %*ph %s %*ph\n", + ret, requesttype, request, 2, &value, 2, &index, 2, &size, + (requesttype & USB_DIR_IN) ? "<<<" : ">>>", size, ctx->buf); + if (ret < 0) + goto err_mutex_unlock; + + if (request == CMD_READ) + memcpy(data, ctx->buf, size); + + usleep_range(1000, 2000); /* Avoid I2C errors */ + + mutex_unlock(&d->usb_mutex); + + return 0; + +err_mutex_unlock: + mutex_unlock(&d->usb_mutex); + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; +} + +static int gl861_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], +int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + struct usb_interface *intf = d->intf; + struct gl861 *ctx = d_to_priv(d); + int ret; + u8 request, *data; + u16 value, index, size; + + /* XXX: I2C adapter maximum data lengths are not tested */ + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + /* I2C write */ + if (msg[0].len < 2 || msg[0].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + + if (msg[0].len == 2) { + request = CMD_WRITE_SHORT; + value |= msg[0].buf[1]; + size = 0; + data = NULL; + } else { + request = CMD_WRITE; + size = msg[0].len - 1; + data = &msg[0].buf[1]; + } + + ret = gl861_ctrl_msg(d, request, value, index, data, size); + } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + /* I2C write + read */ + if (msg[0].len > 1 || msg[1].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + request = CMD_READ; + + ret = gl861_ctrl_msg(d, request, value, index, +msg[1].buf, msg[1].len); + } else { + /* Unsupported I2C message */ + dev_dbg(&intf->dev, "
Re: [PATCH] dvb-usb-v2/gl861: fix wrong memcpy
On 8/22/19 5:00 AM, Akihiro TSUKADA wrote: Hi, I suspect all whole friio_reset() function is not needed as it has worked even I/O has been broken. It worked because the old driver (that I rmmod'ed before installing the testing driver) properly init'ed the device. If I re-plug it (or reboot), it does not work. So it is needed. Also tuner I2C adapter is implemented wrong (I think I mentioned that earlier). As tuner sits behind demod I2C-adapter/gate that whole logic should be on demod driver. But according to USB packet capture logs of the windows version, it makes eccentric use of USB messages ('bRequest' field), that (I believe) necessitates the current implementation, as I mentioned in the past thread. That is because it has 2 i2c write methods - one using only usb_control_msg() header and other header + payload data. When 1 or 2 byte long i2c message is send it is wise to use only "header" to reduce IO as it could carry needed data. Anyhow, I will send patch soon which adds needed logic to i2c adapter. Then it is easier to understand. regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb-usb-v2/gl861: fix wrong memcpy
On 8/17/19 4:22 PM, Akihiro TSUKADA wrote: Could you please test the patch and check if the return results are now consistent and that it won't break anything? I have tested the patch and it worked without problems. Testd-by: Akihiro Tsukada I could not noticed the bug because the device was registered without any error messages, and it seemed to work even with the bug. (Though actually I was wrong and missed that the device does not work after reboot or re-plugging). After applying this patch, I have confirmed that the device now works after reboot/re-plugging without any problems. note: The patched func: gl861_i2c_read_ex was used in device's early init, called from d->props->power_ctrl (from dvb_usbv2_init). But dvb_usbv2_init does not check the return value of it, and if the device had been initialized previously it can work even with the interrupted init process in power_ctrl(). I suspect all whole friio_reset() function is not needed as it has worked even I/O has been broken. Also tuner I2C adapter is implemented wrong (I think I mentioned that earlier). As tuner sits behind demod I2C-adapter/gate that whole logic should be on demod driver. regards Antti -- http://palosaari.fi/
[PATCH] msi2500: assign SPI bus number dynamically
SPI bus number must be assigned dynamically for each device, otherwise it will crash when multiple devices are plugged to system. Cc: sta...@vger.kernel.org Reported-and-tested-by: syzbot+c60ddb60b685777d9...@syzkaller.appspotmail.com Signed-off-by: Antti Palosaari --- drivers/media/usb/msi2500/msi2500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 65be6f140fe8..1c60dfb647e5 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -1230,7 +1230,7 @@ static int msi2500_probe(struct usb_interface *intf, } dev->master = master; - master->bus_num = 0; + master->bus_num = -1; master->num_chipselect = 1; master->transfer_one_message = msi2500_transfer_one_message; spi_master_set_devdata(master, dev); -- 2.21.0
Re: [PATCH] media: tm6000: Spelling s/diconencted/diconnected/
On 7/31/19 4:41 PM, Geert Uytterhoeven wrote: Signed-off-by: Geert Uytterhoeven --- drivers/media/usb/tm6000/tm6000-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c index 23df50aa0a4af6da..9a0ffe678524987c 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/media/usb/tm6000/tm6000-cards.c @@ -1328,7 +1328,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, /* * tm6000_usb_disconnect() - * called when the device gets diconencted + * called when the device gets diconnected disconnected ? For the both patches. * video device will be unregistered on v4l2_close in case it is still open */ static void tm6000_usb_disconnect(struct usb_interface *interface) regards Antti -- http://palosaari.fi/
Re: [PATCH 1/2] dvbsky: add support for "Mygica T230C v2"
On 6/25/19 6:41 PM, JP wrote: On 6/25/19 1:16 PM, Sean Young wrote: On Sun, Jun 16, 2019 at 02:39:29AM +0200, Jan Pieter van Woerkom wrote: From: Jan Pieter van Woerkom Adds support for the "Mygica T230C v2" into the "dvbsky" driver. A small enhancement is also needed in the si2168 demodulator driver, and a USB device ID in dvb-usb-ids.h . This is v3.3 of the proposed patch, based on feedback from Sean Young and Antti Palosaari. Tested by patch author on a T230C v2. Tested by Frank Rysanek on a T230C v2: can tune into locally available DVB-T and DVB-T2 muxes, video and audio playback works. Applies cleanly against Linux 5.1.10 . The T230C v2 hardware needs a mode of the si2168 chip to be set for which the si2168 driver previously had no support. This patch uses a specific measure to configure this on the T230C v2 hardware only - see the flag passed via the ts_mode attribute and its dependency on USB_PID_MYGICA_T230C2. Other devices using the si2168 demodulator driver are not affected in any way. Signed-off-by: Jan Pieter van Woerkom Tested-by: Frank Rysanek --- diff -ru a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c --- a/drivers/media/dvb-frontends/si2168.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/dvb-frontends/si2168.c 2019-06-08 19:47:32.385526558 +0200 @@ -91,8 +91,18 @@ dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + /* set manual value */ + if (dev->ts_mode | SI2168_TS_CLK_MANUAL) { This looks wrong. Should it not be "dev->ts_mode & SI2168_TS_CLK_MANUAL"? Now the expression is always true. You're absolutely right. Silly me. What now? Correct and repost? yes, and next indentation looks also wrong + memcpy(cmd.args, "\x14\x00\x0d\x10\xe8\x03", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + if (ret) + return ret; + } /* set TS_MODE property */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6); + cmd.args[4] = dev->ts_mode & (SI2168_TS_CLK_AUTO|SI2168_TS_CLK_MANUAL); if (acquire) cmd.args[4] |= dev->ts_mode; else diff -ru a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h --- a/drivers/media/dvb-frontends/si2168.h 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/dvb-frontends/si2168.h 2019-06-08 19:32:52.400320490 +0200 @@ -39,6 +39,8 @@ #define SI2168_TS_PARALLEL 0x06 #define SI2168_TS_SERIAL 0x03 #define SI2168_TS_TRISTATE 0x00 +#define SI2168_TS_CLK_AUTO 0x10 +#define SI2168_TS_CLK_MANUAL 0x20 u8 ts_mode; /* TS clock inverted */ Thanks, Sean Thank you, Jan Pieter. regards Antti -- http://palosaari.fi/
Re: si2168 gapped clock
Hello, On 6/18/19 7:47 PM, Marc Gonzalez wrote: Hello, In the qcom SoC, the TS interface has two modes of operation. - with 3 signals (clk, valid, data) - with 4 signals (clk, valid, data, sync) In the si2168 short datasheet, I can see a diagram with these 4 signals. My question is: how do we configure the si2168 demod to be in the first mode or the second mode? Is it the ts_clock_gapped parameter? ts_clock_gapped=0 means no sync ts_clock_gapped=1 means with sync ??? Regards. In general for mpeg ts you will need: data + clock + valid : when clock is running continuously or data + clock : when clock is running only when there is data Valid is used to tell there is new data when clock is running continuously - when valid signal is not set there is no data even clock is running. When only data and clock lines are used, clock is ran only when there is data. Sync signal is set for beginning of every TS packet (and it is not hardly needed if you parse ts data by software for example). Thus ts_clock_gapped means demod will flip clock only when there is data to feed ==> no need for valid signal. Configuring demod to first *or* second mode should be just ts_clock_gapped=false. regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/12/19 11:07 PM, Frantisek Rysanek wrote: On 12 Jun 2019 at 1:28, Antti Palosaari wrote: [...] What is that T230C2 stick? JP has already explained the details, how that name was arrived at. As previously suggested, I can call it T230C v2 in the descriptive texts. I'd suggest keeping T230C2 in the USB ID macro (or suggest a more appropriate name for the macro). Here in CZ, a company called Abacus imports and distributes consumer electronics gadgets under a private brand "EvolveO" - and this is how the "rebadged OEM Mygica" has reached me. http://m.evolveo.com/cz/sigma-t2 This particular T2 dongle is "allover the place" around here, no other dongle is this broadly available. (Well on our modest market. We're a nation of 10M people.) Naming sounds like a DVB-C2 capable, but I found only T230C model from MyGica site. The local brand's site only mentions DVB-T2. The 2-page "brief datasheet" of the si2168 that's publically available only mentions DVB-C, apart from T/T2. And also patch should be split to two logical parts, first add manual ts frequency support to si2168 and then other patch which adds device itself. I'll try to find some time and massage that approach into the code. I have read all the past attempts (example patches) and the maintainer's polite objections. And which are tuner and demod versions/revisions used for that device? That's reported in dmesg if memory serves... I'll try to find the answer. Frank Rysanek Yeah, all-in-all: 1) name it T230C v2 2) use manual ts clock speed And according to old usb sniffs from pctv 292e [Si2168B] default manual ts clock is set to 7.2MHz, which means 57.6Mbit/s datarate, it should be quite optimal for DVB-T2 max. In theory it could be a little higher only when 10MHz channel bandwidth and most less error correction FEC in use. And currently driver is using some config that uses dynamic ts clock which clocks only when there is data to feed. For some reason, usb-ts-bridge does not understand that and manual configuration is needed (ts valid or ts-sync connection?). If possible use 7.2MHz, if not: set to 10MHz. regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/13/19 4:15 AM, JP wrote: And according to old usb sniffs from pctv 292e [Si2168B] default manual ts clock is set to 7.2MHz, which means 57.6Mbit/s datarate, it should be quite optimal for DVB-T2 max. In theory it could be a little higher only when 10MHz channel bandwidth and most less error correction FEC in use. And currently driver is using some config that uses dynamic ts clock which clocks only when there is data to feed. For some reason, usb-ts-bridge does not understand that and manual configuration is needed (ts valid or ts-sync connection?). If possible use 7.2MHz, if not: set to 10MHz. That's perfectly alright with me. I'm now testing that 7.2Mhz value. Hold on. The driver crashes with the 7.2Mhz value! That was totally not what I ever expected. Recompiled the whole kernel: crashes again. Then tried on debian kernel 4.19: same thing. Food for thought? It should sure never crash the kernel. Changing a ts bitrate no, no, no, you trapped a hidden bug. Found where it is :] regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/12/19 2:49 AM, Antti Palosaari wrote: + /* set ts clock freq to 10Mhz */ + memcpy(cmd.args, "\x14\x00\x0d\x10\xe8\x03", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + if (ret) return ret; + 0x03e8 is 1000 and value used is 10 000Hz steps ==> 10 000 000 = 10MHz. Which means 8bit parallel ts bus has capacity of 80Mbit/s which sounds correct max for DVB-T2. What is default value set to that property? Many times those default values are just correct. The default value *is* 10Mhz. On all other si2168 hardware this does not need to be set but for some reason, on this hardware it needs to be set manually. The actual value has been scanned from the running windows driver by means of a USB logger. My best guess is that this whole si2168 driver has been written with the help of such a logger. If the default value is already 10MHz then there is no need to set it at all. I am a bit too lazy to start dumping that default value out from the chip atm. Looked from the pctv 292e sniffs, and it seems default is set to 7.2MHz. $ grep -A1 "\\\x14\\\x00\\\x0d\\\x10" l.c i2c_master_send_DEMOD(s->client, "\x14\x00\x0d\x10\xd0\x02", 6); //014597 i2c_master_recv_DEMOD(s->client, buf, 4); //014598 "\x80\x00\xd0\x02" T230C windows driver does not touch that value at all. In theory default may be different on different chip revisions, but I haven't never seen such case so I suspect it is still 7.2MHz on your device. regards Antti -- http://palosaari.fi/
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/12/19 2:27 AM, JP wrote: On 6/12/19 12:28 AM, Antti Palosaari wrote: On 6/8/19 5:49 AM, JP wrote: I made the Mygica T230c2 work on kernel 5.1.7, but I have no idea how to submit this. http://jpvw.nl/pub/test/dvb/linux-5.1.7-t230c2.patch Please can someone help me out. It looks like the extra code in the demodulator does not effect other drivers that use it. Tested with a T230, they bothseem to work OK. Jan Pieter van Woerkom diff -ru a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c --- a/drivers/media/dvb-frontends/si2168.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/dvb-frontends/si2168.c 2019-06-07 22:49:21.226337473 +0200 @@ -91,8 +91,16 @@ dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + /* set ts clock freq to 10Mhz */ + memcpy(cmd.args, "\x14\x00\x0d\x10\xe8\x03", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + if (ret) return ret; + 0x03e8 is 1000 and value used is 10 000Hz steps ==> 10 000 000 = 10MHz. Which means 8bit parallel ts bus has capacity of 80Mbit/s which sounds correct max for DVB-T2. What is default value set to that property? Many times those default values are just correct. The default value *is* 10Mhz. On all other si2168 hardware this does not need to be set but for some reason, on this hardware it needs to be set manually. The actual value has been scanned from the running windows driver by means of a USB logger. My best guess is that this whole si2168 driver has been written with the help of such a logger. If the default value is already 10MHz then there is no need to set it at all. I am a bit too lazy to start dumping that default value out from the chip atm. /* set TS_MODE property */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6); + cmd.args[4] = dev->ts_mode & 0x30; if (acquire) cmd.args[4] |= dev->ts_mode; else And that enables use of own value. Anyhow, I don't like idea of piggybacking those "magic" bits on ts mode configuration variable. It is better to define own configuration value for ts clock on use it when it is set. In other cases I immediately would agree, but actually, all bits in the hw register correspond with the bits in the ts mode configuration variable. When I discovered that, I could not resist making use of it. The code is very compact this way. But all right, you convinced me. I guess :-) You may also define flag for TS_MODE_PARALLEL_10MHZ or so. IIRC, (haven't been there for a while), it is 10 and 16MHz used widely for parallel ts. So freely configurable ts clock may be a bit overkill still :] Own media/dvb wide datatype for ts settings could be nice if someone ever wants to implement such. diff -ru a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c 2019-06-07 16:47:32.141530489 +0200 @@ -560,6 +560,9 @@ si2168_config.i2c_adapter = &i2c_adapter; si2168_config.fe = &adap->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; + if (d->udev->descriptor.idProduct == USB_PID_MYGICA_T230C2) + si2168_config.ts_mode |= 0x20; si2168_config.ts_clock_inv = 1; state->i2c_client_demod = dvb_module_probe("si2168", NULL, @@ -799,6 +802,9 @@ { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C, &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C", RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, + &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C2", + RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, { } }; MODULE_DEVICE_TABLE(usb, dvbsky_id_table); diff -ru a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h --- a/include/media/dvb-usb-ids.h 2019-06-04 07:59:45.0 +0200 +++ b/include/media/dvb-usb-ids.h 2019-06-06 17:32:32.159187000 +0200 @@ -387,6 +387,7 @@ #define USB_PID_MYGICA_D689 0xd811 #define USB_PID_MYGICA_T230 0xc688 #define USB_PID_MYGICA_T230C 0xc689 +#define USB_PID_MYGICA_T230C2 0xc68a #define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 #define USB_PID_ELGATO_EYETV_DTT 0x0021 #define USB_PID_ELGATO_EYETV_DTT_2 0x003f What is that T230C2 stick? Naming sounds like a DVB-C2 capable, but I found only T230C model from MyGica site. Where I can get one? The T230C2 is sold as T230C. Apart from that it needs the TS clock be set they both are exactly the same. I bought it from China. Aliexpress. The old T230C is out of stock. And al
Re: [PATCH] dvb_usb_dvbsky: Mygica T230C2 add support for T230C hw version 2
On 6/8/19 5:49 AM, JP wrote: I made the Mygica T230c2 work on kernel 5.1.7, but I have no idea how to submit this. http://jpvw.nl/pub/test/dvb/linux-5.1.7-t230c2.patch Please can someone help me out. It looks like the extra code in the demodulator does not effect other drivers that use it. Tested with a T230, they bothseem to work OK. Jan Pieter van Woerkom diff -ru a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c --- a/drivers/media/dvb-frontends/si2168.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/dvb-frontends/si2168.c 2019-06-07 22:49:21.226337473 +0200 @@ -91,8 +91,16 @@ dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + /* set ts clock freq to 10Mhz */ + memcpy(cmd.args, "\x14\x00\x0d\x10\xe8\x03", 6); + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + if (ret) return ret; + 0x03e8 is 1000 and value used is 10 000Hz steps ==> 10 000 000 = 10MHz. Which means 8bit parallel ts bus has capacity of 80Mbit/s which sounds correct max for DVB-T2. What is default value set to that property? Many times those default values are just correct. /* set TS_MODE property */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6); + cmd.args[4] = dev->ts_mode & 0x30; if (acquire) cmd.args[4] |= dev->ts_mode; else And that enables use of own value. Anyhow, I don't like idea of piggybacking those "magic" bits on ts mode configuration variable. It is better to define own configuration value for ts clock on use it when it is set. diff -ru a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c 2019-06-04 07:59:45.0 +0200 +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c 2019-06-07 16:47:32.141530489 +0200 @@ -560,6 +560,9 @@ si2168_config.i2c_adapter = &i2c_adapter; si2168_config.fe = &adap->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; + if (d->udev->descriptor.idProduct == USB_PID_MYGICA_T230C2) + si2168_config.ts_mode |= 0x20; si2168_config.ts_clock_inv = 1; state->i2c_client_demod = dvb_module_probe("si2168", NULL, @@ -799,6 +802,9 @@ { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C, &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C", RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, + &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C2", + RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, { } }; MODULE_DEVICE_TABLE(usb, dvbsky_id_table); diff -ru a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h --- a/include/media/dvb-usb-ids.h 2019-06-04 07:59:45.0 +0200 +++ b/include/media/dvb-usb-ids.h 2019-06-06 17:32:32.159187000 +0200 @@ -387,6 +387,7 @@ #define USB_PID_MYGICA_D689 0xd811 #define USB_PID_MYGICA_T230 0xc688 #define USB_PID_MYGICA_T230C 0xc689 +#define USB_PID_MYGICA_T230C2 0xc68a #define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 #define USB_PID_ELGATO_EYETV_DTT 0x0021 #define USB_PID_ELGATO_EYETV_DTT_2 0x003f What is that T230C2 stick? Naming sounds like a DVB-C2 capable, but I found only T230C model from MyGica site. Where I can get one? And also patch should be split to two logical parts, first add manual ts frequency support to si2168 and then other patch which adds device itself. And which are tuner and demod versions/revisions used for that device? regards Antti -- http://palosaari.fi/
Re: [PATCH] media: m88ds3103: serialize reset messages in m88ds3103_set_frontend
On 1/22/19 1:08 PM, James Hutchinson wrote: On Sun, Jan 20, 2019 at 04:43:08PM +0200, Antti Palosaari wrote: On 1/13/19 11:13 PM, James Hutchinson wrote: Ref: https://bugzilla.kernel.org/show_bug.cgi?id=199323 Users are experiencing problems with the DVBSky S960/S960C USB devices since the following commit: 9d659ae: ("locking/mutex: Add lock handoff to avoid starvation") The device malfunctions after running for an indeterminable period of time, and the problem can only be cleared by rebooting the machine. It is possible to encourage the problem to surface by blocking the signal to the LNB. Further debugging revealed the cause of the problem. In the following capture: - thread #1325 is running m88ds3103_set_frontend - thread #42 is running ts2020_stat_work a> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 80 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 08 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 68 3f [42] usb 1-1: dvb_usb_v2_generic_io: <<< 08 ff [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 3d [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff b> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 00 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 21 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 66 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 60 02 10 0b [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 Two i2c messages are sent to perform a reset in m88ds3103_set_frontend: a. 0x07, 0x80 b. 0x07, 0x00 However, as shown in the capture, the regmap mutex is being handed over to another thread (ts2020_stat_work) in between these two messages. From here, the device responds to every i2c message with an 07 message, and will only return to normal operation following a power cycle. Use regmap_multi_reg_write to group the two reset messages, ensuring both are processed before the regmap mutex is unlocked. I tried to reproduce that issue with pctv 461e, which has em28xx usb-interface, but without success. Even when I added some sleep between reset commands and increased tuner statistic polling interval such that it polls all the time, it works correctly. Device has tuner is connected to demod i2c bus, which I think is same for your device (it calls demod i2c mux select for every tuner i2c access). Taking into account tests I made it is probably issue with usb-interface i2c adapter instead - for some reason it stops working and starts returning 07 error all the time. Did any other I2C command succeed after failure? I mean is there any other i2c client on that bus you could test if it fails too on error situation? All in all, fix should be done to usb-interface i2c adapter if possible unless it has proven issue is somewhere else. You could try to add some sleep or repeat to i2c adapter in order to see if it helps. regards Antti -- http://palosaari.fi/ Thanks for taking the time to review my patch. My device is the dvbsky usb s960 which is a pretty popular device and hasn't been working for several users since commit 9d659ae. I did some further investigation and can now see that the issue likely only affects adapters which use the m88ds3103_get_agc_pwm function to get the AGC from the demodulator as part of ts2020_stat_work. This is the 3f message in my original capture, which gets an ff response. [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 68 3f [42] usb 1-1: dvb_usb_v2_generic_io: <<< 08 ff The m88ds3103_get_agc_pwm function looks to be used by a subset of devices and their variants from the dvbsky usb-interface (s960 & s960c), and the cx23885-dvb pci-interface (s950, s950c, s952). The problem does NOT occur if I disable auto-gain correction by removing the following line from dvbsky_s960_attach: ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; I then have the same experience as you; I can add a sleep between the reset commands and increase the tuner statistic polling interval, and it still works correctly. I can also reproduce the issue on older kernels (pre-commit 9d659ae) by adding a sleep between the two reset commands and leaving the agc re
Re: [PATCH 12/13] si2157: add on-demand rf strength func
On 12/29/18 7:51 PM, Brad Love wrote: Add get_rf_strength callback to get RSSI from the tuner. DVBv5 stat cache is updated. Signed-off-by: Brad Love --- drivers/media/tuners/si2157.c | 38 +- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 1737007..f28bf7f 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -752,6 +752,40 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } +static int si2157_get_rf_strength(struct dvb_frontend *fe, u16 *rssi) +{ + struct i2c_client *client = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct si2157_cmd cmd; + int ret; + int strength; + + dev_dbg(&client->dev, "\n"); + + memcpy(cmd.args, "\x42\x00", 2); + cmd.wlen = 2; + cmd.rlen = 12; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = (s8) cmd.args[3] * 1000; + + strength = (s8)cmd.args[3]; + strength = (strength > -80) ? (u16)(strength + 100) : 0; + strength = strength > 80 ? 100 : strength; + + *rssi = (u16)(strength * 0x / 100); + dev_dbg(&client->dev, "%s: strength=%d rssi=%u\n", + __func__, (s8)cmd.args[3], *rssi); + + return 0; +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + static const struct dvb_tuner_ops si2157_ops = { .info = { .name = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158", @@ -765,7 +799,9 @@ static const struct dvb_tuner_ops si2157_ops = { .set_analog_params = si2157_set_analog_params, .get_frequency = si2157_get_frequency, .get_bandwidth = si2157_get_bandwidth, - .get_if_frequency = si2157_get_if_frequency, + .get_if_frequency = si2157_get_if_frequency, + + .get_rf_strength = si2157_get_rf_strength, }; static void si2157_stat_work(struct work_struct *work) Where that is called from? It is also hard to read how you convert dBm RSSI value to some other scale. There is various clamp() macros for limiting value to desired range. __func__ should not be passed to dev_ macros, check some manual how to use. Driver already polls rssi for digital tv, but I assume that is somehow related to analog. regards Antti -- http://palosaari.fi/
Re: [PATCH 04/13] si2157: Add clock and pin setup for si2141
On 12/29/18 7:51 PM, Brad Love wrote: Include some missing setup for si2141 Signed-off-by: Brad Love --- drivers/media/tuners/si2157.c | 17 + 1 file changed, 17 insertions(+) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index f3a60a1..1ad2d42 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -236,6 +236,23 @@ static int si2157_init(struct dvb_frontend *fe) dev_info(&client->dev, "firmware version: %c.%c.%d\n", cmd.args[6], cmd.args[7], cmd.args[8]); + if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { + /* set clock */ + memcpy(cmd.args, "\xc0\x00\x0d", 3); + cmd.wlen = 3; + cmd.rlen = 1; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + /* setup PIN */ + memcpy(cmd.args, "\x12\x80\x80\x85\x00\x81\x00", 7); + cmd.wlen = 7; + cmd.rlen = 7; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + } + /* enable tuner status flags */ memcpy(cmd.args, "\x14\x00\x01\x05\x01\x00", 6); cmd.wlen = 6; Si2141 is working in my understanding, why these are required? regards Antti -- http://palosaari.fi/
Re: [PATCH] media: m88ds3103: serialize reset messages in m88ds3103_set_frontend
On 1/13/19 11:13 PM, James Hutchinson wrote: Ref: https://bugzilla.kernel.org/show_bug.cgi?id=199323 Users are experiencing problems with the DVBSky S960/S960C USB devices since the following commit: 9d659ae: ("locking/mutex: Add lock handoff to avoid starvation") The device malfunctions after running for an indeterminable period of time, and the problem can only be cleared by rebooting the machine. It is possible to encourage the problem to surface by blocking the signal to the LNB. Further debugging revealed the cause of the problem. In the following capture: - thread #1325 is running m88ds3103_set_frontend - thread #42 is running ts2020_stat_work a> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 80 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 08 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 68 3f [42] usb 1-1: dvb_usb_v2_generic_io: <<< 08 ff [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 3d [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff b> [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 07 00 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 21 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff [42] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [42] usb 1-1: dvb_usb_v2_generic_io: >>> 09 01 01 60 66 [42] usb 1-1: dvb_usb_v2_generic_io: <<< 07 ff [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 68 02 03 11 [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 [1325] usb 1-1: dvb_usb_v2_generic_io: >>> 08 60 02 10 0b [1325] usb 1-1: dvb_usb_v2_generic_io: <<< 07 Two i2c messages are sent to perform a reset in m88ds3103_set_frontend: a. 0x07, 0x80 b. 0x07, 0x00 However, as shown in the capture, the regmap mutex is being handed over to another thread (ts2020_stat_work) in between these two messages. From here, the device responds to every i2c message with an 07 message, and will only return to normal operation following a power cycle. Use regmap_multi_reg_write to group the two reset messages, ensuring both are processed before the regmap mutex is unlocked. I tried to reproduce that issue with pctv 461e, which has em28xx usb-interface, but without success. Even when I added some sleep between reset commands and increased tuner statistic polling interval such that it polls all the time, it works correctly. Device has tuner is connected to demod i2c bus, which I think is same for your device (it calls demod i2c mux select for every tuner i2c access). Taking into account tests I made it is probably issue with usb-interface i2c adapter instead - for some reason it stops working and starts returning 07 error all the time. Did any other I2C command succeed after failure? I mean is there any other i2c client on that bus you could test if it fails too on error situation? All in all, fix should be done to usb-interface i2c adapter if possible unless it has proven issue is somewhere else. You could try to add some sleep or repeat to i2c adapter in order to see if it helps. regards Antti -- http://palosaari.fi/
Re: [PATCH 02/13] si2157: Check error status bit on cmd execute
On 12/29/18 7:51 PM, Brad Love wrote: Check error status bit on command execute, if error bit is set return -EAGAIN. Ignore -EAGAIN in probe during device check. Signed-off-by: Brad Love --- drivers/media/tuners/si2157.c | 12 +--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 4855448..3924c42 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -56,14 +56,20 @@ static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd) break; } - dev_dbg(&client->dev, "cmd execution took %d ms\n", + dev_dbg(&client->dev, "cmd execution took %d ms, status=%x\n", jiffies_to_msecs(jiffies) - - (jiffies_to_msecs(timeout) - TIMEOUT)); + (jiffies_to_msecs(timeout) - TIMEOUT), + cmd->args[0]); if (!((cmd->args[0] >> 7) & 0x01)) { ret = -ETIMEDOUT; goto err_mutex_unlock; } + /* check error status bit */ + if (cmd->args[0] & 0x40) { + ret = -EAGAIN; + goto err_mutex_unlock; + } } mutex_unlock(&dev->i2c_mutex); @@ -477,7 +483,7 @@ static int si2157_probe(struct i2c_client *client, cmd.wlen = 0; cmd.rlen = 1; ret = si2157_cmd_execute(client, &cmd); - if (ret) + if (ret && (ret != -EAGAIN)) goto err_kfree; memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops)); So you added check if firmware returns error during command execution, but that error is still skipped during probe, which does not feel correct. Chip should work during probe and ideally driver should ensure it is correct chip. At least you should read some property value or execute some other command without failure. regards Antti -- http://palosaari.fi/
Re: [PATCH 1/4] si2157: add detection of si2177 tuner
On 12/20/18 11:57 PM, Brad Love wrote: Works in ATSC and QAM as is, DVB is completely untested. Firmware required. Signed-off-by: Brad Love --- drivers/media/tuners/si2157.c | 6 ++ drivers/media/tuners/si2157_priv.h | 3 ++- #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" #define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw" - +#define SI2157_A30_FIRMWARE "dvb-tuner-si2157-a30-05.fw" Why you added 05 to that file name? I added that spare number for cases you have to replace firmware to another for some reason thus by default case it should be 01. regards Antti -- http://palosaari.fi/
Re: Regression: DVBSky S960 USB tuner doesn't work in 4.10 or newer
On 04/18/2018 07:49 AM, Olli Salonen wrote: Thank you for your response Peter! Indeed, it seems strange. dvbsky.c driver seems to use mutex_lock in very much the same way as many other drivers. I've now confirmed that I can get a 4.10 kernel with working DVBSky S960 by reverting the following 4 patches: 549bdd3 Revert "locking/mutex: Add lock handoff to avoid starvation" 3210f31 Revert "locking/mutex: Restructure wait loop" 418a170 Revert "locking/mutex: Simplify some ww_mutex code in __mutex_lock_common()" 0b1fb8f Revert "locking/mutex: Enable optimistic spinning of woken waiter" c470abd Linux 4.10 These kind of issues tend to be timing issues very often. Just add some sleeps to i2c adapter algo / usb control messages and test. regards Antti -- http://palosaari.fi/
Re: [PATCH v4] dvb-usb/friio, dvb-usb-v2/gl861: decompose friio and merge with gl861
On 03/30/2018 04:21 PM, Akihiro TSUKADA wrote: I simply cannot see why it cannot work. Just add i2c adapter and suitable logic there. Transaction on your example is simply and there is no problem to implement that kind of logic to demod i2c adapter. I might be totally wrong, but... i2c transactions to a tuner must use: 1. usb_control_msg(request:3) for the first half (write) of reads 2. usb_control_msg(request:1) for the other writes 3. usb_control_msg(request:2) for (all) reads How can the demod driver control the 'request' argument of USB messages that are sent to its parent (not to the demod itself), when the bridge of tc90522 cannot be limited to gl861 (or even to USB) ? I don't understand those control message parts and it is bit too hard to read i2c adapter implementation to get understanding. Could you offer simple 2 sniff examples, register write to demod and register write to tuner. Anyhow, demod i2c adapter gets request from tuner and then does some demod specific i2c algo stuff and then pass proper request to usb-bridge i2c adapter. IIR it was somehing like write_tuner_reg(0xaa, 0xbb); ==> demod i2c algo: * write_demod_reg(0xfe, 0x60) // set tuner i2c addr + start i2c write * write_demod_reg(0xaa, 0xbb) so those command now goes to i2c-bridge i2c algo which uses gl861 i2c algo regards Antti -- http://palosaari.fi/
Re: [PATCH v4 1/5] dvb-frontends/dvb-pll: add i2c driver support
On 03/28/2018 08:00 PM, tsk...@gmail.com wrote: From: Akihiro Tsukada registers the module as an i2c driver, but keeps dvb_pll_attach() untouched for compatibility. Signed-off-by: Akihiro Tsukada --- Changes since v3: - use standard i2c_device_id instead of dvb_pll_config drivers/media/dvb-frontends/dvb-pll.c | 67 +++ drivers/media/dvb-frontends/dvb-pll.h | 24 + 2 files changed, 91 insertions(+) diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index 5553b89b804..e2a93aae04f 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -827,6 +827,73 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, } EXPORT_SYMBOL(dvb_pll_attach); + +static int +dvb_pll_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct dvb_pll_config *cfg; + struct dvb_frontend *fe; + unsigned int desc_id; + + cfg = client->dev.platform_data; + fe = cfg->fe; + i2c_set_clientdata(client, fe); + desc_id = (unsigned int) id->driver_data; + + if (!dvb_pll_attach(fe, client->addr, client->adapter, desc_id)) + return -ENOMEM; + + dev_info(&client->dev, "DVB Simple Tuner attached.\n"); Print used pll chip name here + return 0; +} + +static int dvb_pll_remove(struct i2c_client *client) +{ + struct dvb_frontend *fe; + + fe = i2c_get_clientdata(client); + dvb_pll_release(fe); + return 0; +} + + +static const struct i2c_device_id dvb_pll_id[] = { + {DVB_PLL_THOMSON_DTT7579_NAME,DVB_PLL_THOMSON_DTT7579}, + {DVB_PLL_THOMSON_DTT759X_NAME,DVB_PLL_THOMSON_DTT759X}, + {DVB_PLL_LG_Z201_NAME,DVB_PLL_LG_Z201}, + {DVB_PLL_UNKNOWN_1_NAME, DVB_PLL_UNKNOWN_1}, + {DVB_PLL_TUA6010XS_NAME, DVB_PLL_TUA6010XS}, + {DVB_PLL_ENV57H1XD5_NAME, DVB_PLL_ENV57H1XD5}, + {DVB_PLL_TUA6034_NAME,DVB_PLL_TUA6034}, + {DVB_PLL_TDA665X_NAME,DVB_PLL_TDA665X}, + {DVB_PLL_TDED4_NAME, DVB_PLL_TDED4}, + {DVB_PLL_TDHU2_NAME, DVB_PLL_TDHU2}, + {DVB_PLL_SAMSUNG_TBMV_NAME, DVB_PLL_SAMSUNG_TBMV}, + {DVB_PLL_PHILIPS_SD1878_TDA8261_NAME, DVB_PLL_PHILIPS_SD1878_TDA8261}, + {DVB_PLL_OPERA1_NAME, DVB_PLL_OPERA1}, + {DVB_PLL_SAMSUNG_DTOS403IH102A_NAME, DVB_PLL_SAMSUNG_DTOS403IH102A}, + {DVB_PLL_SAMSUNG_TDTC9251DH0_NAME,DVB_PLL_SAMSUNG_TDTC9251DH0}, + {DVB_PLL_SAMSUNG_TBDU18132_NAME, DVB_PLL_SAMSUNG_TBDU18132}, + {DVB_PLL_SAMSUNG_TBMU24112_NAME, DVB_PLL_SAMSUNG_TBMU24112}, + {DVB_PLL_TDEE4_NAME, DVB_PLL_TDEE4}, + {DVB_PLL_THOMSON_DTT7520X_NAME, DVB_PLL_THOMSON_DTT7520X}, + {} +}; + + +MODULE_DEVICE_TABLE(i2c, dvb_pll_id); + +static struct i2c_driver dvb_pll_driver = { + .driver = { + .name = "dvb_pll", + }, + .probe= dvb_pll_probe, + .remove = dvb_pll_remove, + .id_table = dvb_pll_id, +}; + +module_i2c_driver(dvb_pll_driver); + MODULE_DESCRIPTION("dvb pll library"); MODULE_AUTHOR("Gerd Knorr"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h index ca885e71d2f..e96994bf668 100644 --- a/drivers/media/dvb-frontends/dvb-pll.h +++ b/drivers/media/dvb-frontends/dvb-pll.h @@ -30,6 +30,30 @@ #define DVB_PLL_TDEE418 #define DVB_PLL_THOMSON_DTT7520X 19 +#define DVB_PLL_THOMSON_DTT7579_NAME "dtt7579" +#define DVB_PLL_THOMSON_DTT759X_NAME"dtt759x" +#define DVB_PLL_LG_Z201_NAME"z201" +#define DVB_PLL_UNKNOWN_1_NAME "unknown_1" +#define DVB_PLL_TUA6010XS_NAME "tua6010xs" +#define DVB_PLL_ENV57H1XD5_NAME "env57h1xd5" +#define DVB_PLL_TUA6034_NAME"tua6034" +#define DVB_PLL_TDA665X_NAME"tda665x" +#define DVB_PLL_TDED4_NAME "tded4" +#define DVB_PLL_TDHU2_NAME "tdhu2" +#define DVB_PLL_SAMSUNG_TBMV_NAME "tbmv" +#define DVB_PLL_PHILIPS_SD1878_TDA8261_NAME "sd1878_tda8261" +#define DVB_PLL_OPERA1_NAME "opera1" +#define DVB_PLL_SAMSUNG_DTOS403IH102A_NAME "dtos403ih102a" +#define DVB_PLL_SAMSUNG_TDTC9251DH0_NAME"tdtc9251dh0" +#define DVB_PLL_SAMSUNG_TBDU18132_NAME "tbdu18132" +#define DVB_PLL_SAMSUNG_TBMU24112_NAME "tbmu24112" +#define DVB_PLL_TDEE4_NAME "tdee4" +#define DVB_PLL_THOMSON_DTT7520X_NAME "dtt7520x" Defining these names like that does not give any value. IMHO better to just add those chip names directly to chip id table. + +struct dvb_pll_config { + struct dvb_frontend *fe; +}; + #if IS_REACHABLE(CONFIG_DVB_PLL) /** * Attach a dvb-pll to the
Re: [PATCH v4] dvb-usb/friio, dvb-usb-v2/gl861: decompose friio and merge with gl861
On 03/28/2018 03:37 PM, Akihiro TSUKADA wrote: Hi, thanks for the comment. You should implement i2c adapter to demod driver and not add such glue to that USB-bridge. I mean that "relayed" stuff, i2c communication to tuner via demod. I2C-mux may not work I think as there is no gate-style multiplexing so you probably need plain i2c adapter. There is few examples already on some demod drivers. I am afraid that the glue is actually necessary. host - USB -> gl861 - I2C(1) -> tc90522 (addr:X) \- I2C(2) -> tua6034 (addr:Y) To send an i2c read message to tua6034, one has to issue two transactions: 1. write via I2C(1) to addr:X, [ reg:0xfe, val: Y ] 2. read via I2C(1) from addr:X, [ out_data0, out_data1, ] The problem is that the transaction 1 is (somehow) implemented with the different USB request than the other i2c transactions on I2C(1). (this is confirmed by a packet capture on Windows box). Although tc90522 already creats the i2c adapter for I2C(2), tc90522 cannot know/control the USB implementation of I2C(1), only the bridge driver can do this. I simply cannot see why it cannot work. Just add i2c adapter and suitable logic there. Transaction on your example is simply and there is no problem to implement that kind of logic to demod i2c adapter. If gl861 driver i2c adapter logic is broken it can be fixed easily too. It seems to support only i2c writes with len 1 and 2 bytes, but fixing it should be easy if you has some sniffs. Antti -- http://palosaari.fi/
Re: [PATCH v3 1/5] dvb-frontends/dvb-pll: add i2c driver support
On 03/26/2018 09:06 PM, tsk...@gmail.com wrote: From: Akihiro Tsukada registers the module as an i2c driver, but keeps dvb_pll_attach() untouched for compatibility. Signed-off-by: Akihiro Tsukada --- drivers/media/dvb-frontends/dvb-pll.c | 49 +++ drivers/media/dvb-frontends/dvb-pll.h | 6 + 2 files changed, 55 insertions(+) diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index 5553b89b804..614a5ea3b00 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -827,6 +827,55 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, } EXPORT_SYMBOL(dvb_pll_attach); + +static int +dvb_pll_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct dvb_pll_config *cfg; + struct dvb_frontend *fe; + unsigned int desc_id; + + cfg = client->dev.platform_data; + fe = cfg->fe; + i2c_set_clientdata(client, fe); + desc_id = cfg->desc_id; + + if (!dvb_pll_attach(fe, client->addr, client->adapter, desc_id)) + return -ENOMEM; + + dev_info(&client->dev, "DVB Simple Tuner attached.\n"); + return 0; +} + +static int dvb_pll_remove(struct i2c_client *client) +{ + struct dvb_frontend *fe; + + fe = i2c_get_clientdata(client); + dvb_pll_release(fe); + return 0; +} + + +static const struct i2c_device_id dvb_pll_id[] = { + {"dvb_pll", 0}, + {} +}; + + +MODULE_DEVICE_TABLE(i2c, dvb_pll_id); + +static struct i2c_driver dvb_pll_driver = { + .driver = { + .name = "dvb_pll", + }, + .probe= dvb_pll_probe, + .remove = dvb_pll_remove, + .id_table = dvb_pll_id, +}; + +module_i2c_driver(dvb_pll_driver); + MODULE_DESCRIPTION("dvb pll library"); MODULE_AUTHOR("Gerd Knorr"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h index ca885e71d2f..15bda0d0c15 100644 --- a/drivers/media/dvb-frontends/dvb-pll.h +++ b/drivers/media/dvb-frontends/dvb-pll.h @@ -30,6 +30,12 @@ #define DVB_PLL_TDEE418 #define DVB_PLL_THOMSON_DTT7520X 19 +struct dvb_pll_config { + struct dvb_frontend *fe; + + unsigned int desc_id; +}; + #if IS_REACHABLE(CONFIG_DVB_PLL) /** * Attach a dvb-pll to the supplied frontend structure. Hello Idea is correct, but I would use pll chip names for passing correct pll type for driver - that field is just for that. Like that: static const struct i2c_device_id dvb_pll_id[] = { {"PLL-NAME1", 0}, {"PLL-NAME2", 1}, {"PLL-NAME3", 2}, {} }; See si2157 for example. regards Antti -- http://palosaari.fi/
Re: [PATCH v4] dvb-usb/friio, dvb-usb-v2/gl861: decompose friio and merge with gl861
On 03/27/2018 08:47 PM, tsk...@gmail.com wrote: From: Akihiro Tsukada Friio device contains "gl861" bridge and "tc90522" demod, for which the separate drivers are already in the kernel. But friio driver was monolithic and did not use them, practically copying those features. This patch decomposes friio driver into sub drivers and re-uses existing ones, thus reduces some code. It adds some features to gl861, to support the friio-specific init/config of the devices and implement i2c communications to the tuner via demod with USB vendor requests. You should implement i2c adapter to demod driver and not add such glue to that USB-bridge. I mean that "relayed" stuff, i2c communication to tuner via demod. I2C-mux may not work I think as there is no gate-style multiplexing so you probably need plain i2c adapter. There is few examples already on some demod drivers. regards Antti -- http://palosaari.fi/
[GIT PULL] af9013/af9015 improvements
The following changes since commit 3f127ce11353fd1071cae9b65bc13add6aec6b90: media: em28xx-cards: fix em28xx_duplicate_dev() (2018-03-08 06:06:51 -0500) are available in the Git repository at: git://linuxtv.org/anttip/media_tree.git af9015_pull for you to fetch changes up to 3a11388095b992f0da01238adaec8b68cbad5c09: af9015: correct some coding style issues (2018-03-14 01:32:56 +0200) Antti Palosaari (18): af9013: change lock detection slightly af9013: dvbv5 signal strength af9013: dvbv5 cnr af9013: dvbv5 ber and per af9013: wrap dvbv3 statistics via dvbv5 af9015: fix logging af9013: convert inittabs suitable for regmap_update_bits af9013: add i2c mux adapter for tuner bus af9015: attach demod using i2c binding af9013: remove all legacy media attach releated stuff af9013: add pid filter support af9015: use af9013 demod pid filters af9015: refactor firmware download af9015: refactor copy firmware to slave demod af9015: enhance streaming config dvb-usb-v2: add probe/disconnect callbacks af9015: convert to regmap api af9015: correct some coding style issues drivers/media/dvb-frontends/Kconfig |2 +- drivers/media/dvb-frontends/af9013.c| 909 +--- drivers/media/dvb-frontends/af9013.h| 48 ++--- drivers/media/dvb-frontends/af9013_priv.h | 1558 ++--- drivers/media/usb/dvb-usb-v2/Kconfig|1 + drivers/media/usb/dvb-usb-v2/af9015.c | 985 -- drivers/media/usb/dvb-usb-v2/af9015.h | 20 +- drivers/media/usb/dvb-usb-v2/dvb_usb.h |4 + drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 24 ++- 9 files changed, 1778 insertions(+), 1773 deletions(-) -- http://palosaari.fi/
[PATCH 14/18] af9015: refactor copy firmware to slave demod
Small improvements. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 88 +-- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index ffd4b225e439..1f352307a00a 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -720,79 +720,79 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) struct af9015_state *state = d_to_priv(d); struct usb_interface *intf = d->intf; int ret; - u8 fw_params[4]; - u8 val, i; - struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params), - fw_params }; + unsigned long timeout; + u8 val, firmware_info[4]; + struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, 4, firmware_info}; dev_dbg(&intf->dev, "\n"); - fw_params[0] = state->firmware_size >> 8; - fw_params[1] = state->firmware_size & 0xff; - fw_params[2] = state->firmware_checksum >> 8; - fw_params[3] = state->firmware_checksum & 0xff; + firmware_info[0] = (state->firmware_size >> 8) & 0xff; + firmware_info[1] = (state->firmware_size >> 0) & 0xff; + firmware_info[2] = (state->firmware_checksum >> 8) & 0xff; + firmware_info[3] = (state->firmware_checksum >> 0) & 0xff; - ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], - 0x98be, &val); + /* Check whether firmware is already running */ + ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], 0x98be, &val); if (ret) - goto error; - else - dev_dbg(&intf->dev, "firmware status %02x\n", val); + goto err; - if (val == 0x0c) /* fw is running, no need for download */ - goto exit; + dev_dbg(&intf->dev, "firmware status %02x\n", val); - /* set I2C master clock to fast (to speed up firmware copy) */ - ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */ - if (ret) - goto error; + if (val == 0x0c) + return 0; - msleep(50); + /* Set i2c clock to 625kHz to speed up firmware copy */ + ret = af9015_write_reg(d, 0xd416, 0x04); + if (ret) + goto err; - /* copy firmware */ + /* Copy firmware from master demod to slave demod */ ret = af9015_ctrl_msg(d, &req); - if (ret) + if (ret) { dev_err(&intf->dev, "firmware copy cmd failed %d\n", ret); + goto err; + } - dev_dbg(&intf->dev, "firmware copy done\n"); - - /* set I2C master clock back to normal */ - ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */ + /* Set i2c clock to 125kHz */ + ret = af9015_write_reg(d, 0xd416, 0x14); if (ret) - goto error; + goto err; - /* request boot firmware */ - ret = af9015_write_reg_i2c(d, state->af9013_i2c_addr[1], - 0xe205, 1); - dev_dbg(&intf->dev, "firmware boot cmd status %d\n", ret); + /* Boot firmware */ + ret = af9015_write_reg_i2c(d, state->af9013_i2c_addr[1], 0xe205, 0x01); if (ret) - goto error; + goto err; - for (i = 0; i < 15; i++) { - msleep(100); + /* Poll firmware ready */ + for (val = 0x00, timeout = jiffies + msecs_to_jiffies(1000); +!time_after(jiffies, timeout) && val != 0x0c && val != 0x04;) { + msleep(20); - /* check firmware status */ + /* Check firmware status. 0c=OK, 04=fail */ ret = af9015_read_reg_i2c(d, state->af9013_i2c_addr[1], - 0x98be, &val); - dev_dbg(&intf->dev, "firmware status cmd status %d, firmware status %02x\n", - ret, val); + 0x98be, &val); if (ret) - goto error; + goto err; - if (val == 0x0c || val == 0x04) /* success or fail */ - break; + dev_dbg(&intf->dev, "firmware status %02x\n", val); } + dev_dbg(&intf->dev, "firmware boot took %u ms\n", + jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - 1000)); + if (val == 0x04) { - ret = -ETIMEDOUT; + ret = -ENODEV; dev_err(&intf->dev, "firmware did not run\n"); + goto err; } else if (val != 0x0c) { ret = -ETIMEDOUT; dev_err(&intf->dev, "firmware boot timeout\n"); + goto err; } -error: -exit: + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } -- 2.14.3
[PATCH 07/18] af9013: convert inittabs suitable for regmap_update_bits
Convert inttabs to format (reg, mask, val) which are suitable parameters to pass directly for regmap_update_bits. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 62 +- drivers/media/dvb-frontends/af9013_priv.h | 1488 +++-- 2 files changed, 782 insertions(+), 768 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index e81dc827e1b8..87a55cd67e03 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -843,7 +843,7 @@ static int af9013_init(struct dvb_frontend *fe) int ret, i, len; unsigned int utmp; u8 buf[3]; - const struct af9013_reg_bit *init; + const struct af9013_reg_mask_val *tab; dev_dbg(&client->dev, "\n"); @@ -898,72 +898,66 @@ static int af9013_init(struct dvb_frontend *fe) if (ret) goto err; - /* load OFSM settings */ - dev_dbg(&client->dev, "load ofsm settings\n"); - len = ARRAY_SIZE(ofsm_init); - init = ofsm_init; + /* Demod core settings */ + dev_dbg(&client->dev, "load demod core settings\n"); + len = ARRAY_SIZE(demod_init_tab); + tab = demod_init_tab; for (i = 0; i < len; i++) { - u16 reg = init[i].addr; - u8 mask = GENMASK(init[i].pos + init[i].len - 1, init[i].pos); - u8 val = init[i].val << init[i].pos; - - ret = regmap_update_bits(state->regmap, reg, mask, val); + ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask, +tab[i].val); if (ret) goto err; } - /* load tuner specific settings */ + /* Demod tuner specific settings */ dev_dbg(&client->dev, "load tuner specific settings\n"); switch (state->tuner) { case AF9013_TUNER_MXL5003D: - len = ARRAY_SIZE(tuner_init_mxl5003d); - init = tuner_init_mxl5003d; + len = ARRAY_SIZE(tuner_init_tab_mxl5003d); + tab = tuner_init_tab_mxl5003d; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: case AF9013_TUNER_MXL5007T: - len = ARRAY_SIZE(tuner_init_mxl5005); - init = tuner_init_mxl5005; + len = ARRAY_SIZE(tuner_init_tab_mxl5005); + tab = tuner_init_tab_mxl5005; break; case AF9013_TUNER_ENV77H11D5: - len = ARRAY_SIZE(tuner_init_env77h11d5); - init = tuner_init_env77h11d5; + len = ARRAY_SIZE(tuner_init_tab_env77h11d5); + tab = tuner_init_tab_env77h11d5; break; case AF9013_TUNER_MT2060: - len = ARRAY_SIZE(tuner_init_mt2060); - init = tuner_init_mt2060; + len = ARRAY_SIZE(tuner_init_tab_mt2060); + tab = tuner_init_tab_mt2060; break; case AF9013_TUNER_MC44S803: - len = ARRAY_SIZE(tuner_init_mc44s803); - init = tuner_init_mc44s803; + len = ARRAY_SIZE(tuner_init_tab_mc44s803); + tab = tuner_init_tab_mc44s803; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - len = ARRAY_SIZE(tuner_init_qt1010); - init = tuner_init_qt1010; + len = ARRAY_SIZE(tuner_init_tab_qt1010); + tab = tuner_init_tab_qt1010; break; case AF9013_TUNER_MT2060_2: - len = ARRAY_SIZE(tuner_init_mt2060_2); - init = tuner_init_mt2060_2; + len = ARRAY_SIZE(tuner_init_tab_mt2060_2); + tab = tuner_init_tab_mt2060_2; break; case AF9013_TUNER_TDA18271: case AF9013_TUNER_TDA18218: - len = ARRAY_SIZE(tuner_init_tda18271); - init = tuner_init_tda18271; + len = ARRAY_SIZE(tuner_init_tab_tda18271); + tab = tuner_init_tab_tda18271; break; case AF9013_TUNER_UNKNOWN: default: - len = ARRAY_SIZE(tuner_init_unknown); - init = tuner_init_unknown; + len = ARRAY_SIZE(tuner_init_tab_unknown); + tab = tuner_init_tab_unknown; break; } for (i = 0; i < len; i++) { - u16 reg = init[i].addr; - u8 mask = GENMASK(init[i].pos + init[i].len - 1, init[i].pos); - u8 val = init[i].val << init[i].pos; - - ret = regmap_update_bits(state->regmap, reg, mask, val); + ret = regmap_update_bits(state->regmap, tab[i].reg, tab[i].mask, +tab[i].val);
[PATCH 15/18] af9015: enhance streaming config
Replace static stream settings by one which enables and disables stream interface when needed (TS streaming control). 1) Configure both TS IF and USB endpoints according to current use case 2) Disable streaming USB endpoints when streaming is stopped and enable when streaming is started. Reduces sleep power consumption slightly. 3) Reduce USB buffersize slightly, from 130848 to 98136 bytes Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 220 ++ drivers/media/usb/dvb-usb-v2/af9015.h | 14 +-- 2 files changed, 115 insertions(+), 119 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 1f352307a00a..99e3b14d493e 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -607,11 +607,121 @@ static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, dev_dbg(&intf->dev, "adap %u\n", fe_to_adap(fe)->id); if (d->udev->speed == USB_SPEED_FULL) - stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE; + stream->u.bulk.buffersize = 5 * 188; return 0; } +static int af9015_streaming_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_device *d = fe_to_d(fe); + struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; + int ret; + unsigned int utmp1, utmp2, reg1, reg2; + u8 buf[2]; + const unsigned int adap_id = fe_to_adap(fe)->id; + + dev_dbg(&intf->dev, "adap id %d, onoff %d\n", adap_id, onoff); + + if (state->usb_ts_if_configured[adap_id] == false) { + dev_dbg(&intf->dev, "set usb and ts interface\n"); + + /* USB IF stream settings */ + utmp1 = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4; + utmp2 = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; + + buf[0] = (utmp1 >> 0) & 0xff; + buf[1] = (utmp1 >> 8) & 0xff; + if (adap_id == 0) { + /* 1st USB IF (EP4) stream settings */ + reg1 = 0xdd88; + reg2 = 0xdd0c; + } else { + /* 2nd USB IF (EP5) stream settings */ + reg1 = 0xdd8a; + reg2 = 0xdd0d; + } + + ret = af9015_write_regs(d, reg1, buf, 2); + if (ret) + goto err; + ret = af9015_write_reg(d, reg2, utmp2); + if (ret) + goto err; + + /* TS IF settings */ + if (state->dual_mode) { + ret = af9015_set_reg_bit(d, 0xd50b, 0); + if (ret) + goto err; + ret = af9015_set_reg_bit(d, 0xd520, 4); + if (ret) + goto err; + } else { + ret = af9015_clear_reg_bit(d, 0xd50b, 0); + if (ret) + goto err; + ret = af9015_clear_reg_bit(d, 0xd520, 4); + if (ret) + goto err; + } + + state->usb_ts_if_configured[adap_id] = true; + } + + if (adap_id == 0 && onoff) { + /* Adapter 0 stream on. EP4: clear NAK, enable, clear reset */ + ret = af9015_clear_reg_bit(d, 0xdd13, 5); + if (ret) + goto err; + ret = af9015_set_reg_bit(d, 0xdd11, 5); + if (ret) + goto err; + ret = af9015_clear_reg_bit(d, 0xd507, 2); + if (ret) + goto err; + } else if (adap_id == 1 && onoff) { + /* Adapter 1 stream on. EP5: clear NAK, enable, clear reset */ + ret = af9015_clear_reg_bit(d, 0xdd13, 6); + if (ret) + goto err; + ret = af9015_set_reg_bit(d, 0xdd11, 6); + if (ret) + goto err; + ret = af9015_clear_reg_bit(d, 0xd50b, 1); + if (ret) + goto err; + } else if (adap_id == 0 && !onoff) { + /* Adapter 0 stream off. EP4: set reset, disable, set NAK */ + ret = af9015_set_reg_bit(d, 0xd507, 2); + if (ret) + goto err; + ret = af9015_clear_reg_bit(d, 0xdd11, 5); + if (ret) + goto err; + ret = af9015_set_reg_bit(d, 0xdd13, 5); + if (ret) + goto err; + } else if (adap_id == 1 && !onoff) { +
[PATCH 04/18] af9013: dvbv5 ber and per
Implement dvbv5 ber and per. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 73 +++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index b3d08e437478..a054e39510e0 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -47,6 +47,7 @@ struct af9013_state { unsigned long read_status_jiffies; unsigned long strength_jiffies; unsigned long cnr_jiffies; + unsigned long ber_ucb_jiffies; bool first_tune; bool i2c_gate_state; unsigned int statistics_step:3; @@ -754,7 +755,7 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, stmp1; unsigned int utmp, utmp1, utmp2, utmp3, utmp4; - u8 buf[3]; + u8 buf[7]; dev_dbg(&client->dev, "\n"); @@ -947,6 +948,72 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) break; } + /* BER / PER */ + switch (state->fe_status & FE_HAS_SYNC) { + case FE_HAS_SYNC: + if (time_is_after_jiffies(state->ber_ucb_jiffies + msecs_to_jiffies(2000))) + break; + + /* Check if ber / ucb is ready */ + ret = regmap_read(state->regmap, 0xd391, &utmp); + if (ret) + goto err; + + if (!((utmp >> 4) & 0x01)) { + dev_dbg(&client->dev, "ber not ready\n"); + break; + } + + /* Read value */ + ret = regmap_bulk_read(state->regmap, 0xd385, buf, 7); + if (ret) + goto err; + + utmp1 = buf[4] << 16 | buf[3] << 8 | buf[2] << 0; + utmp2 = (buf[1] << 8 | buf[0] << 0) * 204 * 8; + utmp3 = buf[6] << 8 | buf[5] << 0; + utmp4 = buf[1] << 8 | buf[0] << 0; + + /* Use 1 TS packets for measure */ + if (utmp4 != 1) { + buf[0] = (1 >> 0) & 0xff; + buf[1] = (1 >> 8) & 0xff; + ret = regmap_bulk_write(state->regmap, 0xd385, buf, 2); + if (ret) + goto err; + } + + /* Reset ber / ucb counter */ + ret = regmap_update_bits(state->regmap, 0xd391, 0x20, 0x20); + if (ret) + goto err; + + dev_dbg(&client->dev, "post_bit_error %u, post_bit_count %u\n", + utmp1, utmp2); + dev_dbg(&client->dev, "block_error %u, block_count %u\n", + utmp3, utmp4); + + state->ber_ucb_jiffies = jiffies; + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += utmp1; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += utmp2; + + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += utmp3; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += utmp4; + break; + default: + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + break; + } + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); @@ -1670,6 +1737,10 @@ static int af9013_probe(struct i2c_client *client, c = &state->fe.dtv_property_cache; c->strength.len = 1; c->cnr.len = 1; + c->post_bit_error.len = 1; + c->post_bit_count.len = 1; + c->block_error.len = 1; + c->block_count.len = 1; dev_info(&client->dev, "Afatech AF9013 successfully attached\n"); dev_info(&client->dev, "firmware version: %d.%d.%d.%d\n", -- 2.14.3
[PATCH 18/18] af9015: correct some coding style issues
Correct coding style issues reported mostly by checkpatch.pl. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 172 +- 1 file changed, 88 insertions(+), 84 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 8379ef164fad..39f9ffce3caa 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -72,17 +72,19 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) goto error; } - /* buffer overflow check */ + /* Buffer overflow check */ if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || - (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { + (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { dev_err(&intf->dev, "too much data, cmd %u, len %u\n", req->cmd, req->data_len); ret = -EINVAL; goto error; } - /* write receives seq + status = 2 bytes - read receives seq + status + data = 2 + N bytes */ + /* +* Write receives seq + status = 2 bytes +* Read receives seq + status + data = 2 + N bytes +*/ wlen = REQ_HDR_LEN; rlen = ACK_HDR_LEN; if (write) { @@ -96,8 +98,8 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) rlen = 0; - ret = dvb_usbv2_generic_rw_locked(d, - state->buf, wlen, state->buf, rlen); + ret = dvb_usbv2_generic_rw_locked(d, state->buf, wlen, + state->buf, rlen); if (ret) goto error; @@ -118,7 +120,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) } static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 val) + u8 val) { struct af9015_state *state = d_to_priv(d); struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; @@ -131,7 +133,7 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, } static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, - u8 *val) + u8 *val) { struct af9015_state *state = d_to_priv(d); struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; @@ -144,7 +146,7 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, } static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct af9015_state *state = d_to_priv(d); @@ -154,28 +156,29 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], u8 mbox, addr_len; struct req_t req; -/* -The bus lock is needed because there is two tuners both using same I2C-address. -Due to that the only way to select correct tuner is use demodulator I2C-gate. - - -. AF9015 includes integrated AF9013 demodulator. -. . -.| uC | | demod| . |tuner | -.|| || . || -.| AF9015 | | AF9013/5 | . | MXL5003 | -.||--+I2C---|-/ -|-.-I2C---|| -.|| | | addr 0x38 | . | addr 0xc6 | -.|| | || . || -.|.. -| -| | demod| |tuner | -| || || -| | AF9013 | | MXL5003 | -+I2C---|-/ -|---I2C---|| - | addr 0x3a | | addr 0xc6 | - || || -*/ + /* +* I2C multiplexing: +* There could be two tuners, both using same I2C address. Demodulator +* I2C-gate is only possibility to select correct tuner. +* +* ... +* . AF9015 integrates AF9013 demodulator. +* . . _
[PATCH 03/18] af9013: dvbv5 cnr
Implement dvbv5 cnr. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 88 +-- drivers/media/dvb-frontends/af9013_priv.h | 1 + 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 4cb6371572c5..b3d08e437478 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -46,6 +46,7 @@ struct af9013_state { unsigned long set_frontend_jiffies; unsigned long read_status_jiffies; unsigned long strength_jiffies; + unsigned long cnr_jiffies; bool first_tune; bool i2c_gate_state; unsigned int statistics_step:3; @@ -179,7 +180,6 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) { struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, len; unsigned int utmp; u8 buf[3]; @@ -235,9 +235,6 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) } state->snr = utmp * 10; /* dB/10 */ - c->cnr.stat[0].svalue = 1000 * utmp; - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; - return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); @@ -757,7 +754,7 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, stmp1; unsigned int utmp, utmp1, utmp2, utmp3, utmp4; - u8 buf[2]; + u8 buf[3]; dev_dbg(&client->dev, "\n"); @@ -869,6 +866,87 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) break; } + /* CNR */ + switch (state->fe_status & FE_HAS_VITERBI) { + case FE_HAS_VITERBI: + if (time_is_after_jiffies(state->cnr_jiffies + msecs_to_jiffies(2000))) + break; + + /* Check if cnr ready */ + ret = regmap_read(state->regmap, 0xd2e1, &utmp); + if (ret) + goto err; + + if (!((utmp >> 3) & 0x01)) { + dev_dbg(&client->dev, "cnr not ready\n"); + break; + } + + /* Read value */ + ret = regmap_bulk_read(state->regmap, 0xd2e3, buf, 3); + if (ret) + goto err; + + utmp1 = buf[2] << 16 | buf[1] << 8 | buf[0] << 0; + + /* Read current modulation */ + ret = regmap_read(state->regmap, 0xd3c1, &utmp); + if (ret) + goto err; + + switch ((utmp >> 6) & 3) { + case 0: + /* +* QPSK +* CNR[dB] 13 * -log10((169 - value) / value) + 2.6 +* value [653799, 168], 2.6 / 13 = 3355443 +*/ + utmp1 = clamp(utmp1, 653799U, 168U); + utmp1 = ((u64)(intlog10(utmp1) + - intlog10(169 - utmp1) + + 3355443) * 13 * 1000) >> 24; + break; + case 1: + /* +* QAM-16 +* CNR[dB] 6 * log10((value - 37) / (828000 - value)) + 15.7 +* value [371105, 827999], 15.7 / 6 = 43900382 +*/ + utmp1 = clamp(utmp1, 371105U, 827999U); + utmp1 = ((u64)(intlog10(utmp1 - 37) + - intlog10(828000 - utmp1) + + 43900382) * 6 * 1000) >> 24; + break; + case 2: + /* +* QAM-64 +* CNR[dB] 8 * log10((value - 193000) / (425000 - value)) + 23.8 +* value [193246, 424999], 23.8 / 8 = 49912218 +*/ + utmp1 = clamp(utmp1, 193246U, 424999U); + utmp1 = ((u64)(intlog10(utmp1 - 193000) + - intlog10(425000 - utmp1) + + 49912218) * 8 * 1000) >> 24; + break; + default: + dev_dbg(&client->dev, "invalid modulation %u\n", + (utmp >> 6) & 3); + utmp1 = 0; + break; + } + + dev_dbg(&client->dev, "cnr %u\n&
[PATCH 10/18] af9013: remove all legacy media attach releated stuff
No one is binding that driver through media attach so remove it and all related dead code. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 80 drivers/media/dvb-frontends/af9013.h | 42 --- 2 files changed, 7 insertions(+), 115 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index d55c5f67ce0f..15af3e9482df 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -48,7 +48,6 @@ struct af9013_state { u32 dvbv3_ber; u32 dvbv3_ucblocks; bool first_tune; - bool i2c_gate_state; }; static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) @@ -1031,45 +1030,6 @@ static int af9013_sleep(struct dvb_frontend *fe) return ret; } -static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) -{ - int ret; - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - - dev_dbg(&client->dev, "enable %d\n", enable); - - /* gate already open or close */ - if (state->i2c_gate_state == enable) - return 0; - - if (state->ts_mode == AF9013_TS_MODE_USB) - ret = regmap_update_bits(state->regmap, 0xd417, 0x08, -enable << 3); - else - ret = regmap_update_bits(state->regmap, 0xd607, 0x04, -enable << 2); - if (ret) - goto err; - - state->i2c_gate_state = enable; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static void af9013_release(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - - dev_dbg(&client->dev, "\n"); - - i2c_unregister_device(client); -} - static const struct dvb_frontend_ops af9013_ops; static int af9013_download_firmware(struct af9013_state *state) @@ -1172,40 +1132,6 @@ static int af9013_download_firmware(struct af9013_state *state) return ret; } -/* - * XXX: That is wrapper to af9013_probe() via driver core in order to provide - * proper I2C client for legacy media attach binding. - * New users must use I2C client binding directly! - */ -struct dvb_frontend *af9013_attach(const struct af9013_config *config, - struct i2c_adapter *i2c) -{ - struct i2c_client *client; - struct i2c_board_info board_info; - struct af9013_platform_data pdata; - - pdata.clk = config->clock; - pdata.tuner = config->tuner; - pdata.if_frequency = config->if_frequency; - pdata.ts_mode = config->ts_mode; - pdata.ts_output_pin = 7; - pdata.spec_inv = config->spec_inv; - memcpy(&pdata.api_version, config->api_version, sizeof(pdata.api_version)); - memcpy(&pdata.gpio, config->gpio, sizeof(pdata.gpio)); - pdata.attach_in_use = true; - - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "af9013", sizeof(board_info.type)); - board_info.addr = config->i2c_addr; - board_info.platform_data = &pdata; - client = i2c_new_device(i2c, &board_info); - if (!client || !client->dev.driver) - return NULL; - - return pdata.get_dvb_frontend(client); -} -EXPORT_SYMBOL(af9013_attach); - static const struct dvb_frontend_ops af9013_ops = { .delsys = { SYS_DVBT }, .info = { @@ -1231,8 +1157,6 @@ static const struct dvb_frontend_ops af9013_ops = { FE_CAN_MUTE_TS }, - .release = af9013_release, - .init = af9013_init, .sleep = af9013_sleep, @@ -1245,8 +1169,6 @@ static const struct dvb_frontend_ops af9013_ops = { .read_signal_strength = af9013_read_signal_strength, .read_ber = af9013_read_ber, .read_ucblocks = af9013_read_ucblocks, - - .i2c_gate_ctrl = af9013_i2c_gate_ctrl, }; static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client) @@ -1546,8 +1468,6 @@ static int af9013_probe(struct i2c_client *client, /* Create dvb frontend */ memcpy(&state->fe.ops, &af9013_ops, sizeof(state->fe.ops)); - if (!pdata->attach_in_use) - state->fe.ops.release = NULL; state->fe.demodulator_priv = state; /* Setup callbacks */ diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h index ea63ff9242f2..8144d4270b58 100644 --- a/drivers/media/dvb-frontends/af9013.h +++ b/drivers/media/dvb-frontends/af9013.h @@ -38,13 +38,6 @@ * @api_version: Firmware API version. * @gpio: GPIOs. * @g
[PATCH 05/18] af9013: wrap dvbv3 statistics via dvbv5
Driver has calculated dvbv5 statistics, so use those as a base for legacy dvbv3 statistics. Wrap and convert needed values to dvbv3, remove old dvbv3 statistic implementations. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 306 +++--- drivers/media/dvb-frontends/af9013_priv.h | 68 --- 2 files changed, 22 insertions(+), 352 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index a054e39510e0..e81dc827e1b8 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -33,12 +33,6 @@ struct af9013_state { u8 api_version[4]; u8 gpio[4]; - /* tuner/demod RF and IF AGC limits used for signal strength calc */ - u8 signal_strength_en, rf_50, rf_80, if_50, if_80; - u16 signal_strength; - u32 ber; - u32 ucblocks; - u16 snr; u32 bandwidth_hz; enum fe_status fe_status; /* RF and IF AGC limits used for signal strength calc */ @@ -48,10 +42,12 @@ struct af9013_state { unsigned long strength_jiffies; unsigned long cnr_jiffies; unsigned long ber_ucb_jiffies; + u16 dvbv3_snr; + u16 dvbv3_strength; + u32 dvbv3_ber; + u32 dvbv3_ucblocks; bool first_tune; bool i2c_gate_state; - unsigned int statistics_step:3; - struct delayed_work statistics_work; }; static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) @@ -106,228 +102,6 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) return ret; } -static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret; - - dev_dbg(&client->dev, "\n"); - - /* reset and start BER counter */ - ret = regmap_update_bits(state->regmap, 0xd391, 0x10, 0x10); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret; - unsigned int utmp; - u8 buf[5]; - - dev_dbg(&client->dev, "\n"); - - /* check if error bit count is ready */ - ret = regmap_read(state->regmap, 0xd391, &utmp); - if (ret) - goto err; - - if (!((utmp >> 4) & 0x01)) { - dev_dbg(&client->dev, "not ready\n"); - return 0; - } - - ret = regmap_bulk_read(state->regmap, 0xd387, buf, 5); - if (ret) - goto err; - - state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0]; - state->ucblocks += (buf[4] << 8) | buf[3]; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_snr_start(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret; - - dev_dbg(&client->dev, "\n"); - - /* start SNR meas */ - ret = regmap_update_bits(state->regmap, 0xd2e1, 0x08, 0x08); - if (ret) - goto err; - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - -static int af9013_statistics_snr_result(struct dvb_frontend *fe) -{ - struct af9013_state *state = fe->demodulator_priv; - struct i2c_client *client = state->client; - int ret, i, len; - unsigned int utmp; - u8 buf[3]; - u32 snr_val; - const struct af9013_snr *uninitialized_var(snr_lut); - - dev_dbg(&client->dev, "\n"); - - /* check if SNR ready */ - ret = regmap_read(state->regmap, 0xd2e1, &utmp); - if (ret) - goto err; - - if (!((utmp >> 3) & 0x01)) { - dev_dbg(&client->dev, "not ready\n"); - return 0; - } - - /* read value */ - ret = regmap_bulk_read(state->regmap, 0xd2e3, buf, 3); - if (ret) - goto err; - - snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; - - /* read current modulation */ - ret = regmap_read(state->regmap, 0xd3c1, &utmp); - if (ret) - goto err; - - switch ((utmp >> 6) & 3) { - case 0: - len = ARRAY_SIZE(qpsk_snr_lut); - snr_lut = qpsk_snr_lut; - break; - case 1: - len = ARRAY_SIZE(qam16_snr_lut);
[PATCH 06/18] af9015: fix logging
Pass correct device to dev_* logging functions, which allows us to remove redundant KBUILD_MODNAME and __func__ parameters from log format. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 160 +- 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 8013659c41b1..7e4cce05b911 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -29,6 +29,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) #define REQ_HDR_LEN 8 /* send header size */ #define ACK_HDR_LEN 2 /* rece header size */ struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret, wlen, rlen; u8 write = 1; @@ -66,8 +67,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) case BOOT: break; default: - dev_err(&d->udev->dev, "%s: unknown command=%d\n", - KBUILD_MODNAME, req->cmd); + dev_err(&intf->dev, "unknown cmd %d\n", req->cmd); ret = -EIO; goto error; } @@ -75,8 +75,8 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) /* buffer overflow check */ if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) || (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) { - dev_err(&d->udev->dev, "%s: too much data; cmd=%d len=%d\n", - KBUILD_MODNAME, req->cmd, req->data_len); + dev_err(&intf->dev, "too much data, cmd %u, len %u\n", + req->cmd, req->data_len); ret = -EINVAL; goto error; } @@ -103,8 +103,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) /* check status */ if (rlen && state->buf[1]) { - dev_err(&d->udev->dev, "%s: command failed=%d\n", - KBUILD_MODNAME, state->buf[1]); + dev_err(&intf->dev, "cmd failed %u\n", state->buf[1]); ret = -EIO; goto error; } @@ -206,6 +205,7 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int ret; u16 addr; u8 mbox, addr_len; @@ -307,15 +307,14 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = af9015_ctrl_msg(d, &req); } else { ret = -EOPNOTSUPP; - dev_dbg(&d->udev->dev, "%s: unknown msg, num %u\n", - __func__, num); + dev_dbg(&intf->dev, "unknown msg, num %u\n", num); } if (ret) goto err; return num; err: - dev_dbg(&d->udev->dev, "%s: failed %d\n", __func__, ret); + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } @@ -331,6 +330,7 @@ static struct i2c_algorithm af9015_i2c_algo = { static int af9015_identify_state(struct dvb_usb_device *d, const char **name) { + struct usb_interface *intf = d->intf; int ret; u8 reply; struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply}; @@ -339,7 +339,7 @@ static int af9015_identify_state(struct dvb_usb_device *d, const char **name) if (ret) return ret; - dev_dbg(&d->udev->dev, "%s: reply=%02x\n", __func__, reply); + dev_dbg(&intf->dev, "reply %02x\n", reply); if (reply == 0x02) ret = WARM; @@ -353,10 +353,12 @@ static int af9015_download_firmware(struct dvb_usb_device *d, const struct firmware *fw) { struct af9015_state *state = d_to_priv(d); + struct usb_interface *intf = d->intf; int i, len, remaining, ret; struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; u16 checksum = 0; - dev_dbg(&d->udev->dev, "%s:\n", __func__); + + dev_dbg(&intf->dev, "\n"); /* calc checksum */ for (i = 0; i < fw->size; i++) @@ -378,9 +380,8 @@ static int af9015_download_firmware(struct dvb_usb_device *d, ret = af9015_ctrl_msg(d, &req); if (ret) { - dev_err(&d->udev->dev, - "%s: firmware download failed=%
[PATCH 12/18] af9015: use af9013 demod pid filters
PID filters are moved to af9013 demod driver as those are property of demod. As pid filters are now implemented correctly by demod driver, we could enable pid filter support for possible slave demod too on dual tuner configuration. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 49 +-- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index f07aa42535e5..8e2f704c6ca5 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -474,10 +474,6 @@ static int af9015_read_config(struct dvb_usb_device *d) state->dual_mode = val; dev_dbg(&intf->dev, "ts mode %02x\n", state->dual_mode); - /* disable 2nd adapter because we don't have PID-filters */ - if (d->udev->speed == USB_SPEED_FULL) - state->dual_mode = 0; - state->af9013_i2c_addr[0] = AF9015_I2C_DEMOD; if (state->dual_mode) { @@ -1045,43 +1041,28 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) { - struct dvb_usb_device *d = adap_to_d(adap); - struct usb_interface *intf = d->intf; + struct af9015_state *state = adap_to_priv(adap); + struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; int ret; - dev_dbg(&intf->dev, "onoff %d\n", onoff); - - if (onoff) - ret = af9015_set_reg_bit(d, 0xd503, 0); - else - ret = af9015_clear_reg_bit(d, 0xd503, 0); + mutex_lock(&state->fe_mutex); + ret = pdata->pid_filter_ctrl(adap->fe[0], onoff); + mutex_unlock(&state->fe_mutex); return ret; } -static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, - int onoff) +static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, +u16 pid, int onoff) { - struct dvb_usb_device *d = adap_to_d(adap); - struct usb_interface *intf = d->intf; + struct af9015_state *state = adap_to_priv(adap); + struct af9013_platform_data *pdata = &state->af9013_pdata[adap->id]; int ret; - u8 idx; - - dev_dbg(&intf->dev, "index %d, pid %04x, onoff %d\n", - index, pid, onoff); - ret = af9015_write_reg(d, 0xd505, (pid & 0xff)); - if (ret) - goto error; - - ret = af9015_write_reg(d, 0xd506, (pid >> 8)); - if (ret) - goto error; - - idx = ((index & 0x1f) | (1 << 5)); - ret = af9015_write_reg(d, 0xd504, idx); + mutex_lock(&state->fe_mutex); + ret = pdata->pid_filter(adap->fe[0], index, pid, onoff); + mutex_unlock(&state->fe_mutex); -error: return ret; } @@ -1448,6 +1429,12 @@ static struct dvb_usb_device_properties af9015_props = { .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE), }, { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = af9015_pid_filter, + .pid_filter_ctrl = af9015_pid_filter_ctrl, + .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE), }, }, -- 2.14.3
[PATCH 08/18] af9013: add i2c mux adapter for tuner bus
Add muxed i2c adapter for demod tuner i2c bus gate control. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/Kconfig | 2 +- drivers/media/dvb-frontends/af9013.c | 126 +- drivers/media/dvb-frontends/af9013.h | 1 + drivers/media/dvb-frontends/af9013_priv.h | 1 + 4 files changed, 111 insertions(+), 19 deletions(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 687086cdb870..0712069fd9fe 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -462,7 +462,7 @@ config DVB_TDA10048 config DVB_AF9013 tristate "Afatech AF9013 demodulator" - depends on DVB_CORE && I2C + depends on DVB_CORE && I2C && I2C_MUX select REGMAP default m if !MEDIA_SUBDRV_AUTOSELECT help diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 87a55cd67e03..d55c5f67ce0f 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -23,6 +23,7 @@ struct af9013_state { struct i2c_client *client; struct regmap *regmap; + struct i2c_mux_core *muxc; struct dvb_frontend fe; u32 clk; u8 tuner; @@ -1257,9 +1258,65 @@ static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client) return &state->fe; } +static struct i2c_adapter *af9013_get_i2c_adapter(struct i2c_client *client) +{ + struct af9013_state *state = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return state->muxc->adapter[0]; +} + +/* + * XXX: Hackish solution. We use virtual register, reg bit 16, to carry info + * about i2c adapter locking. Own locking is needed because i2c mux call has + * already locked i2c adapter. + */ +static int af9013_select(struct i2c_mux_core *muxc, u32 chan) +{ + struct af9013_state *state = i2c_mux_priv(muxc); + struct i2c_client *client = state->client; + int ret; + + dev_dbg(&client->dev, "\n"); + + if (state->ts_mode == AF9013_TS_MODE_USB) + ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x08); + else + ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x04); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + +static int af9013_deselect(struct i2c_mux_core *muxc, u32 chan) +{ + struct af9013_state *state = i2c_mux_priv(muxc); + struct i2c_client *client = state->client; + int ret; + + dev_dbg(&client->dev, "\n"); + + if (state->ts_mode == AF9013_TS_MODE_USB) + ret = regmap_update_bits(state->regmap, 0x1d417, 0x08, 0x00); + else + ret = regmap_update_bits(state->regmap, 0x1d607, 0x04, 0x00); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + /* Own I2C access routines needed for regmap as chip uses extra command byte */ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, - const u8 *val, int len) + const u8 *val, int len, u8 lock) { int ret; u8 buf[21]; @@ -1281,7 +1338,12 @@ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, buf[1] = (reg >> 0) & 0xff; buf[2] = cmd; memcpy(&buf[3], val, len); - ret = i2c_transfer(client->adapter, msg, 1); + + if (lock) + i2c_lock_adapter(client->adapter); + ret = __i2c_transfer(client->adapter, msg, 1); + if (lock) + i2c_unlock_adapter(client->adapter); if (ret < 0) { goto err; } else if (ret != 1) { @@ -1296,7 +1358,7 @@ static int af9013_wregs(struct i2c_client *client, u8 cmd, u16 reg, } static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg, - u8 *val, int len) + u8 *val, int len, u8 lock) { int ret; u8 buf[3]; @@ -1317,7 +1379,12 @@ static int af9013_rregs(struct i2c_client *client, u8 cmd, u16 reg, buf[0] = (reg >> 8) & 0xff; buf[1] = (reg >> 0) & 0xff; buf[2] = cmd; - ret = i2c_transfer(client->adapter, msg, 2); + + if (lock) + i2c_lock_adapter(client->adapter); + ret = __i2c_transfer(client->adapter, msg, 2); + if (lock) + i2c_unlock_adapter(client->adapter); if (ret < 0) { goto err; } else if (ret != 2) { @@ -1337,25 +1404,27 @@ static int af9013_regmap_write(void *context, const void *data, size_t count)
[PATCH 01/18] af9013: change lock detection slightly
Whilst rewritten largely, the basic logic remains same with one exception: do not return immediately on success case. We are going to add statistics that function and cannot return too early. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 55 ++-- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index b8f3ebfc3e27..30cf837058da 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -752,45 +752,44 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; int ret; - unsigned int utmp; + unsigned int utmp, utmp1; /* * Return status from the cache if it is younger than 2000ms with the * exception of last tune is done during 4000ms. */ - if (time_is_after_jiffies( - state->read_status_jiffies + msecs_to_jiffies(2000)) && - time_is_before_jiffies( - state->set_frontend_jiffies + msecs_to_jiffies(4000)) - ) { - *status = state->fe_status; - return 0; + if (time_is_after_jiffies(state->read_status_jiffies + msecs_to_jiffies(2000)) && + time_is_before_jiffies(state->set_frontend_jiffies + msecs_to_jiffies(4000))) { + *status = state->fe_status; } else { - *status = 0; - } + /* MPEG2 lock */ + ret = regmap_read(state->regmap, 0xd507, &utmp); + if (ret) + goto err; - /* MPEG2 lock */ - ret = regmap_read(state->regmap, 0xd507, &utmp); - if (ret) - goto err; + if ((utmp >> 6) & 0x01) { + utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + } else { + /* TPS lock */ + ret = regmap_read(state->regmap, 0xd330, &utmp); + if (ret) + goto err; - if ((utmp >> 6) & 0x01) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_LOCK; + if ((utmp >> 3) & 0x01) + utmp1 = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI; + else + utmp1 = 0; + } - if (!*status) { - /* TPS lock */ - ret = regmap_read(state->regmap, 0xd330, &utmp); - if (ret) - goto err; + dev_dbg(&client->dev, "fe_status %02x\n", utmp1); - if ((utmp >> 3) & 0x01) - *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI; - } + state->read_status_jiffies = jiffies; - state->fe_status = *status; - state->read_status_jiffies = jiffies; + state->fe_status = utmp1; + *status = utmp1; + } return 0; err: -- 2.14.3
[PATCH 17/18] af9015: convert to regmap api
Use regmap for chip register access. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/Kconfig | 1 + drivers/media/usb/dvb-usb-v2/af9015.c | 209 ++ drivers/media/usb/dvb-usb-v2/af9015.h | 2 + 3 files changed, 115 insertions(+), 97 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 0e4944b2b0f4..09a52aae299a 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -16,6 +16,7 @@ config DVB_USB_V2 config DVB_USB_AF9015 tristate "Afatech AF9015 DVB-T USB2.0 support" depends on DVB_USB_V2 + select REGMAP select DVB_AF9013 select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 99e3b14d493e..8379ef164fad 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -117,31 +117,6 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) return ret; } -static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val, - u8 len) -{ - struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len) -{ - struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len, - val}; - return af9015_ctrl_msg(d, &req); -} - -static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val) -{ - return af9015_write_regs(d, addr, &val, 1); -} - -static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val) -{ - return af9015_read_regs(d, addr, val, 1); -} - static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, u8 val) { @@ -168,38 +143,6 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, return af9015_ctrl_msg(d, &req); } -static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op) -{ - int ret; - u8 val, mask = 0x01; - - ret = af9015_read_reg(d, addr, &val); - if (ret) - return ret; - - mask <<= bit; - if (op) { - /* set bit */ - val |= mask; - } else { - /* clear bit */ - mask ^= 0xff; - val &= mask; - } - - return af9015_write_reg(d, addr, val); -} - -static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 1); -} - -static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit) -{ - return af9015_do_reg_bit(d, addr, bit, 0); -} - static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { @@ -642,76 +585,73 @@ static int af9015_streaming_ctrl(struct dvb_frontend *fe, int onoff) reg1 = 0xdd8a; reg2 = 0xdd0d; } - - ret = af9015_write_regs(d, reg1, buf, 2); + ret = regmap_bulk_write(state->regmap, reg1, buf, 2); if (ret) goto err; - ret = af9015_write_reg(d, reg2, utmp2); + ret = regmap_write(state->regmap, reg2, utmp2); if (ret) goto err; /* TS IF settings */ if (state->dual_mode) { - ret = af9015_set_reg_bit(d, 0xd50b, 0); - if (ret) - goto err; - ret = af9015_set_reg_bit(d, 0xd520, 4); - if (ret) - goto err; + utmp1 = 0x01; + utmp2 = 0x10; } else { - ret = af9015_clear_reg_bit(d, 0xd50b, 0); - if (ret) - goto err; - ret = af9015_clear_reg_bit(d, 0xd520, 4); - if (ret) - goto err; + utmp1 = 0x00; + utmp2 = 0x00; } + ret = regmap_update_bits(state->regmap, 0xd50b, 0x01, utmp1); + if (ret) + goto err; + ret = regmap_update_bits(state->regmap, 0xd520, 0x10, utmp2); + if (ret) + goto err; state->usb_ts_if_configured[adap_id] = true; } if (adap_id == 0 && onoff) { /* Adapter 0 stream on. EP4: clear NAK, enable, clear reset */ - ret = af9015_clear_reg_bit(d, 0xdd13, 5); +
[PATCH 16/18] dvb-usb-v2: add probe/disconnect callbacks
Add probe and disconnect callbacks that behaves similarly than ones used commonly on Linux driver model. We need those to get early / late access to driver in order to use normal probe time stuff, like regmap, extra bus adapters and so. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/dvb_usb.h | 4 drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 24 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index d2e80537b2f7..3fd6cc0d6340 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -203,6 +203,8 @@ struct dvb_usb_adapter_properties { * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for * receive * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message + * @probe: like probe on driver model + * @disconnect: like disconnect on driver model * @identify_state: called to determine the firmware state (cold or warm) and * return possible firmware file name to be loaded * @firmware: name of the firmware file to be loaded @@ -239,6 +241,8 @@ struct dvb_usb_device_properties { u8 generic_bulk_ctrl_endpoint_response; unsigned int generic_bulk_ctrl_delay; + int (*probe)(struct dvb_usb_device *); + void (*disconnect)(struct dvb_usb_device *); #define WARM 0 #define COLD 1 int (*identify_state) (struct dvb_usb_device *, const char **); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 2bf3bd81280a..afdcdbf005e9 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -854,8 +854,6 @@ static int dvb_usbv2_exit(struct dvb_usb_device *d) dvb_usbv2_remote_exit(d); dvb_usbv2_adapter_exit(d); dvb_usbv2_i2c_exit(d); - kfree(d->priv); - kfree(d); return 0; } @@ -934,7 +932,7 @@ int dvb_usbv2_probe(struct usb_interface *intf, if (intf->cur_altsetting->desc.bInterfaceNumber != d->props->bInterfaceNumber) { ret = -ENODEV; - goto err_free_all; + goto err_kfree_d; } mutex_init(&d->usb_mutex); @@ -946,10 +944,16 @@ int dvb_usbv2_probe(struct usb_interface *intf, dev_err(&d->udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); ret = -ENOMEM; - goto err_free_all; + goto err_kfree_d; } } + if (d->props->probe) { + ret = d->props->probe(d); + if (ret) + goto err_kfree_priv; + } + if (d->props->identify_state) { const char *name = NULL; ret = d->props->identify_state(d, &name); @@ -1001,6 +1005,12 @@ int dvb_usbv2_probe(struct usb_interface *intf, return 0; err_free_all: dvb_usbv2_exit(d); + if (d->props->disconnect) + d->props->disconnect(d); +err_kfree_priv: + kfree(d->priv); +err_kfree_d: + kfree(d); err: dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret); return ret; @@ -1021,6 +1031,12 @@ void dvb_usbv2_disconnect(struct usb_interface *intf) dvb_usbv2_exit(d); + if (d->props->disconnect) + d->props->disconnect(d); + + kfree(d->priv); + kfree(d); + pr_info("%s: '%s:%s' successfully deinitialized and disconnected\n", KBUILD_MODNAME, drvname, devname); kfree(devname); -- 2.14.3
[PATCH 09/18] af9015: attach demod using i2c binding
af9013 demod driver has i2c binding. Use it. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 158 -- drivers/media/usb/dvb-usb-v2/af9015.h | 4 +- 2 files changed, 96 insertions(+), 66 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 7e4cce05b911..f07aa42535e5 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -148,8 +148,8 @@ static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, struct af9015_state *state = d_to_priv(d); struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val}; - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) + if (addr == state->af9013_i2c_addr[0] || + addr == state->af9013_i2c_addr[1]) req.addr_len = 3; return af9015_ctrl_msg(d, &req); @@ -161,8 +161,8 @@ static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg, struct af9015_state *state = d_to_priv(d); struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val}; - if (addr == state->af9013_config[0].i2c_addr || - addr == state->af9013_config[1].i2c_addr) + if (addr == state->af9013_i2c_addr[0] || + addr == state->af9013_i2c_addr[1]) req.addr_len = 3; return af9015_ctrl_msg(d, &req); @@ -258,7 +258,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto err; } - if (msg[0].addr == state->af9013_config[0].i2c_addr) + if (msg[0].addr == state->af9013_i2c_addr[0]) req.cmd = WRITE_MEMORY; else req.cmd = WRITE_I2C; @@ -276,7 +276,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto err; } - if (msg[0].addr == state->af9013_config[0].i2c_addr) + if (msg[0].addr == state->af9013_i2c_addr[0]) req.cmd = READ_MEMORY; else req.cmd = READ_I2C; @@ -293,7 +293,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. ret = -EOPNOTSUPP; goto err; } - if (msg[0].addr == state->af9013_config[0].i2c_addr) { + if (msg[0].addr == state->af9013_i2c_addr[0]) { ret = -EINVAL; goto err; } @@ -478,7 +478,7 @@ static int af9015_read_config(struct dvb_usb_device *d) if (d->udev->speed == USB_SPEED_FULL) state->dual_mode = 0; - state->af9013_config[0].i2c_addr = AF9015_I2C_DEMOD; + state->af9013_i2c_addr[0] = AF9015_I2C_DEMOD; if (state->dual_mode) { /* read 2nd demodulator I2C address */ @@ -487,7 +487,7 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret) goto error; - state->af9013_config[1].i2c_addr = val >> 1; + state->af9013_i2c_addr[1] = val >> 1; } for (i = 0; i < state->dual_mode + 1; i++) { @@ -500,20 +500,20 @@ static int af9015_read_config(struct dvb_usb_device *d) goto error; switch (val) { case 0: - state->af9013_config[i].clock = 2880; + state->af9013_pdata[i].clk = 2880; break; case 1: - state->af9013_config[i].clock = 2048; + state->af9013_pdata[i].clk = 2048; break; case 2: - state->af9013_config[i].clock = 2800; + state->af9013_pdata[i].clk = 2800; break; case 3: - state->af9013_config[i].clock = 2500; + state->af9013_pdata[i].clk = 2500; break; } - dev_dbg(&intf->dev, "[%d] xtal %02x, clock %u\n", - i, val, state->af9013_config[i].clock); + dev_dbg(&intf->dev, "[%d] xtal %02x, clk %u\n", + i, val, state->af9013_pdata[i].clk); /* IF frequency */ req.addr = AF9015_EEPROM_IF1H + offset; @@ -521,17 +521,17 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret)
[PATCH 02/18] af9013: dvbv5 signal strength
Implement dvbv5 signal strength estimate. We know tuner dependent -80dBm and -50dBm agc values, construct line equation and use it to map agc value to signal strength estimate. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 83 +++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 30cf837058da..4cb6371572c5 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -41,8 +41,11 @@ struct af9013_state { u16 snr; u32 bandwidth_hz; enum fe_status fe_status; + /* RF and IF AGC limits used for signal strength calc */ + u8 strength_en, rf_agc_50, rf_agc_80, if_agc_50, if_agc_80; unsigned long set_frontend_jiffies; unsigned long read_status_jiffies; + unsigned long strength_jiffies; bool first_tune; bool i2c_gate_state; unsigned int statistics_step:3; @@ -751,8 +754,12 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; - int ret; - unsigned int utmp, utmp1; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret, stmp1; + unsigned int utmp, utmp1, utmp2, utmp3, utmp4; + u8 buf[2]; + + dev_dbg(&client->dev, "\n"); /* * Return status from the cache if it is younger than 2000ms with the @@ -791,6 +798,77 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status) *status = utmp1; } + /* Signal strength */ + switch (state->strength_en) { + case 0: + /* Check if we support signal strength */ + ret = regmap_read(state->regmap, 0x9bee, &utmp); + if (ret) + goto err; + + if ((utmp >> 0) & 0x01) { + /* Read agc values for signal strength estimation */ + ret = regmap_read(state->regmap, 0x9bbd, &utmp1); + if (ret) + goto err; + ret = regmap_read(state->regmap, 0x9bd0, &utmp2); + if (ret) + goto err; + ret = regmap_read(state->regmap, 0x9be2, &utmp3); + if (ret) + goto err; + ret = regmap_read(state->regmap, 0x9be4, &utmp4); + if (ret) + goto err; + + state->rf_agc_50 = utmp1; + state->rf_agc_80 = utmp2; + state->if_agc_50 = utmp3; + state->if_agc_80 = utmp4; + dev_dbg(&client->dev, + "rf_agc_50 %u, rf_agc_80 %u, if_agc_50 %u, if_agc_80 %u\n", + utmp1, utmp2, utmp3, utmp4); + + state->strength_en = 1; + } else { + /* Signal strength is not supported */ + state->strength_en = 2; + break; + } + /* Fall through */ + case 1: + if (time_is_after_jiffies(state->strength_jiffies + msecs_to_jiffies(2000))) + break; + + /* Read value */ + ret = regmap_bulk_read(state->regmap, 0xd07c, buf, 2); + if (ret) + goto err; + + /* +* Construct line equation from tuner dependent -80/-50 dBm agc +* limits and use it to map current agc value to dBm estimate +*/ + #define agc_gain (buf[0] + buf[1]) + #define agc_gain_50dbm (state->rf_agc_50 + state->if_agc_50) + #define agc_gain_80dbm (state->rf_agc_80 + state->if_agc_80) + stmp1 = 3 * (agc_gain - agc_gain_80dbm) / + (agc_gain_50dbm - agc_gain_80dbm) - 8; + + dev_dbg(&client->dev, + "strength %d, agc_gain %d, agc_gain_50dbm %d, agc_gain_80dbm %d\n", + stmp1, agc_gain, agc_gain_50dbm, agc_gain_80dbm); + + state->strength_jiffies = jiffies; + + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = stmp1; + break; + default: + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + break; + } + return 0; err: dev_dbg(&client->dev, "fail
[PATCH 13/18] af9015: refactor firmware download
Small revise, no functional changes. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 39 +++ 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 8e2f704c6ca5..ffd4b225e439 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -350,52 +350,47 @@ static int af9015_identify_state(struct dvb_usb_device *d, const char **name) } static int af9015_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) + const struct firmware *firmware) { struct af9015_state *state = d_to_priv(d); struct usb_interface *intf = d->intf; - int i, len, remaining, ret; + int ret, i, rem; struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; - u16 checksum = 0; + u16 checksum; dev_dbg(&intf->dev, "\n"); - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; + /* Calc checksum, we need it when copy firmware to slave demod */ + for (i = 0, checksum = 0; i < firmware->size; i++) + checksum += firmware->data[i]; - state->firmware_size = fw->size; + state->firmware_size = firmware->size; state->firmware_checksum = checksum; - #define FW_ADDR 0x5100 /* firmware start address */ - #define LEN_MAX 55 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - - req.data_len = len; - req.data = (u8 *) &fw->data[fw->size - remaining]; - req.addr = FW_ADDR + fw->size - remaining; - + #define LEN_MAX (BUF_LEN - REQ_HDR_LEN) /* Max payload size */ + for (rem = firmware->size; rem > 0; rem -= LEN_MAX) { + req.data_len = min(LEN_MAX, rem); + req.data = (u8 *) &firmware->data[firmware->size - rem]; + req.addr = 0x5100 + firmware->size - rem; ret = af9015_ctrl_msg(d, &req); if (ret) { dev_err(&intf->dev, "firmware download failed %d\n", ret); - goto error; + goto err; } } - /* firmware loaded, request boot */ req.cmd = BOOT; req.data_len = 0; ret = af9015_ctrl_msg(d, &req); if (ret) { dev_err(&intf->dev, "firmware boot failed %d\n", ret); - goto error; + goto err; } -error: + return 0; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } -- 2.14.3
[PATCH 11/18] af9013: add pid filter support
af9013 demod has pid filter. Add support for it. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 52 drivers/media/dvb-frontends/af9013.h | 5 2 files changed, 57 insertions(+) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 15af3e9482df..482bce49819a 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -1171,6 +1171,56 @@ static const struct dvb_frontend_ops af9013_ops = { .read_ucblocks = af9013_read_ucblocks, }; +static int af9013_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct af9013_state *state = fe->demodulator_priv; + struct i2c_client *client = state->client; + int ret; + + dev_dbg(&client->dev, "onoff %d\n", onoff); + + ret = regmap_update_bits(state->regmap, 0xd503, 0x01, onoff); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + +static int af9013_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, +int onoff) +{ + struct af9013_state *state = fe->demodulator_priv; + struct i2c_client *client = state->client; + int ret; + u8 buf[2]; + + dev_dbg(&client->dev, "index %d, pid %04x, onoff %d\n", + index, pid, onoff); + + if (pid > 0x1fff) { + /* 0x2000 is kernel virtual pid for whole ts (all pids) */ + ret = 0; + goto err; + } + + buf[0] = (pid >> 0) & 0xff; + buf[1] = (pid >> 8) & 0xff; + ret = regmap_bulk_write(state->regmap, 0xd505, buf, 2); + if (ret) + goto err; + ret = regmap_write(state->regmap, 0xd504, onoff << 5 | index << 0); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&client->dev, "failed %d\n", ret); + return ret; +} + static struct dvb_frontend *af9013_get_dvb_frontend(struct i2c_client *client) { struct af9013_state *state = i2c_get_clientdata(client); @@ -1473,6 +1523,8 @@ static int af9013_probe(struct i2c_client *client, /* Setup callbacks */ pdata->get_dvb_frontend = af9013_get_dvb_frontend; pdata->get_i2c_adapter = af9013_get_i2c_adapter; + pdata->pid_filter = af9013_pid_filter; + pdata->pid_filter_ctrl = af9013_pid_filter_ctrl; /* Init stats to indicate which stats are supported */ c = &state->fe.dtv_property_cache; diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h index 8144d4270b58..165ae29ccac4 100644 --- a/drivers/media/dvb-frontends/af9013.h +++ b/drivers/media/dvb-frontends/af9013.h @@ -38,6 +38,9 @@ * @api_version: Firmware API version. * @gpio: GPIOs. * @get_dvb_frontend: Get DVB frontend callback. + * @get_i2c_adapter: Get I2C adapter. + * @pid_filter_ctrl: Control PID filter. + * @pid_filter: Set PID to PID filter. */ struct af9013_platform_data { /* @@ -78,6 +81,8 @@ struct af9013_platform_data { struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *); struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *); + int (*pid_filter_ctrl)(struct dvb_frontend *, int); + int (*pid_filter)(struct dvb_frontend *, u8, u16, int); }; /* -- 2.14.3
Re: [PATCH] media: dvb-usb-v2: stop using coherent memory for URBs
On 03/08/2018 09:09 PM, Mauro Carvalho Chehab wrote: There's no need to use coherent buffers there. So, let the DVB core do the allocation. That should give some performance gain outside x86. Hello! I am not familiar with that change, but I think you know what you do. Feel free to apply! regards Antti Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/usb_urb.c | 17 - 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c index dce2b97efce4..b0499f95ec45 100644 --- a/drivers/media/usb/dvb-usb-v2/usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c @@ -155,8 +155,7 @@ static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream) stream->props.u.bulk.buffersize, usb_urb_complete, stream); - stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - stream->urb_list[i]->transfer_dma = stream->dma_addr[i]; + stream->urb_list[i]->transfer_flags = URB_FREE_BUFFER; stream->urbs_initialized++; } return 0; @@ -187,13 +186,12 @@ static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) urb->complete = usb_urb_complete; urb->pipe = usb_rcvisocpipe(stream->udev, stream->props.endpoint); - urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->transfer_flags = URB_ISO_ASAP | URB_FREE_BUFFER; urb->interval = stream->props.u.isoc.interval; urb->number_of_packets = stream->props.u.isoc.framesperurb; urb->transfer_buffer_length = stream->props.u.isoc.framesize * stream->props.u.isoc.framesperurb; urb->transfer_buffer = stream->buf_list[i]; - urb->transfer_dma = stream->dma_addr[i]; for (j = 0; j < stream->props.u.isoc.framesperurb; j++) { urb->iso_frame_desc[j].offset = frame_offset; @@ -212,11 +210,7 @@ static int usb_free_stream_buffers(struct usb_data_stream *stream) if (stream->state & USB_STATE_URB_BUF) { while (stream->buf_num) { stream->buf_num--; - dev_dbg(&stream->udev->dev, "%s: free buf=%d\n", - __func__, stream->buf_num); - usb_free_coherent(stream->udev, stream->buf_size, - stream->buf_list[stream->buf_num], - stream->dma_addr[stream->buf_num]); + stream->buf_list[stream->buf_num] = NULL; } } @@ -236,9 +230,7 @@ static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, __func__, num * size); for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { - stream->buf_list[stream->buf_num] = usb_alloc_coherent( - stream->udev, size, GFP_ATOMIC, - &stream->dma_addr[stream->buf_num]); + stream->buf_list[stream->buf_num] = kzalloc(size, GFP_ATOMIC); if (!stream->buf_list[stream->buf_num]) { dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n", __func__, stream->buf_num); @@ -250,7 +242,6 @@ static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, __func__, stream->buf_num, stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]); - memset(stream->buf_list[stream->buf_num], 0, size); stream->state |= USB_STATE_URB_BUF; } -- http://palosaari.fi/
Re: [PATCH] Fix for hanging si2168 in PCTV 292e, making code match
On 03/07/2018 06:39 PM, Ron Economos wrote: I'm almost 100% sure that the patch I submitted (and was committed in Linux 4.16-rc1) for the si2168 fixes Nigel's issue. I would suggest that Nigel's patch be retired. https://github.com/torvalds/linux/blob/master/drivers/media/dvb-frontends/si2168.c media: [RESEND] media: dvb-frontends: Add delay to Si2168 restart On faster CPUs a delay is required after the resume command and the restart command. Without the delay, the restart command often returns -EREMOTEIO and the Si2168 does not restart. Note that this patch fixes the same issue as https://patchwork.linuxtv.org/patch/44304/, but I believe my udelay() fix addresses the actual problem. Signed-off-by: Ron Economos Signed-off-by: Mauro Carvalho Chehab Ron Yes, you are likely correct! Patch is already applied, but however I think it should be something like usleep_range(100, ~0) in order to allow scheduler optimize resources as upper limit of delay is not critical at all. See Documentation/timers/timers-howto.txt regards Antti -- http://palosaari.fi/
Re: [PATCH] Fix for hanging si2168 in PCTV 292e, making the code match
On 12/14/2017 04:48 PM, Mauro Carvalho Chehab wrote: Em Tue, 19 Sep 2017 13:13:52 +0100 Nigel Kettlewell escreveu: [re-sending as plain text] Fix for hanging si2168 in PCTV 292e USB, making the code match the comment. Using firmware v4.0.11 the 292e would work once and then hang on subsequent attempts to view DVB channels, until physically unplugged and plugged back in. With this patch, the warm state is reset for v4.0.11 and it appears to work both on the first attempt and on subsequent attempts. It is comment which is wrong. With firmware 4.0.11 it works well without need of download it every time. But firmware 4.0.19 needs to be downloaded every time after device is put to sleep. Probably your issue is coming from some other reason. (Patch basis Linux 4.11.9 f82a53b87594f460f2dd9983eeb851a5840e8df8) Patch is missing a Signed-off-by. See: https://elinux.org/Developer_Certificate_Of_Origin). --- drivers/media/dvb-frontends/si2168.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 680ba06..523acd1 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -582,7 +582,7 @@ static int si2168_sleep(struct dvb_frontend *fe) dev->active = false; /* Firmware B 4.0-11 or later loses warm state during sleep */ - if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) + if (dev->version >= ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) dev->warm = false; memcpy(cmd.args, "\x13", 1); -- 2.9.4 Thanks, Mauro regards Antti -- http://palosaari.fi/
Re: [PATCH v2 1/2] si2168: Add spectrum inversion property
On 01/18/2018 03:58 AM, Brad Love wrote: On 2018-01-17 16:08, Brad Love wrote: On 2018-01-17 16:02, Antti Palosaari wrote: On 01/17/2018 11:52 PM, Brad Love wrote: Some tuners produce inverted spectrum, but the si2168 is not currently set up to accept it. This adds an optional parameter to set the frontend up to receive inverted spectrum. Parameter is optional and only boards who enable inversion will utilize this. Signed-off-by: Brad Love --- Changes since v1: - Embarassing build failure due to missing declaration. drivers/media/dvb-frontends/si2168.c | 3 +++ drivers/media/dvb-frontends/si2168.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index c041e79..048b815 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -213,6 +213,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe) struct i2c_client *client = fe->demodulator_priv; struct si2168_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct si2168_config *config = client->dev.platform_data; hmmm, are you sure platform data pointer points is const? I usually tend to store all config information to device state. Then there is no need to care if pointer is valid or not anymore. And inversion happens when those wires are cross-connected It just dawned on me that the platform_data is stack allocated and therefore not safe to access outside of probe. I will fix this momentarily. I was informed by one of our hardware guys that the two models in patch 2/2 are inverted spectrum, so I guess they have wires cross-connected. I can verify this again to be sure. Hello Antti, I have confirmation. No 'cross-connected' / swapped differential pair polarities (if that's what you meant) on the IF pins. The si2157 inverted spectrum output is configurable though, and Hauppauge have the tuner set up to output inverted. Sounds like it was a decision based on interoperability with older demods. yeah, that was what I was thinking for. That board single tuner and two demods which other demod does not support if spectrum inversion? If there is just si2168 and si2157, you can set both to invert or both to non-invert - the end result is same. Antti -- http://palosaari.fi/
Re: [PATCH v2 1/2] si2168: Add spectrum inversion property
On 01/17/2018 11:52 PM, Brad Love wrote: Some tuners produce inverted spectrum, but the si2168 is not currently set up to accept it. This adds an optional parameter to set the frontend up to receive inverted spectrum. Parameter is optional and only boards who enable inversion will utilize this. Signed-off-by: Brad Love --- Changes since v1: - Embarassing build failure due to missing declaration. drivers/media/dvb-frontends/si2168.c | 3 +++ drivers/media/dvb-frontends/si2168.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index c041e79..048b815 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -213,6 +213,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe) struct i2c_client *client = fe->demodulator_priv; struct si2168_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct si2168_config *config = client->dev.platform_data; hmmm, are you sure platform data pointer points is const? I usually tend to store all config information to device state. Then there is no need to care if pointer is valid or not anymore. And inversion happens when those wires are cross-connected int ret; struct si2168_cmd cmd; u8 bandwidth, delivery_system; @@ -339,6 +340,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe) memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6); cmd.args[4] = delivery_system | bandwidth; + if (config->spectral_inversion) + cmd.args[5] |= 1; cmd.wlen = 6; cmd.rlen = 4; ret = si2168_cmd_execute(client, &cmd); diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index f48f0fb..d519edd 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -46,6 +46,9 @@ struct si2168_config { /* TS clock gapped */ bool ts_clock_gapped; + + /* Inverted spectrum */ + bool spectral_inversion; }; #endif -- http://palosaari.fi/
Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
On 01/16/2018 10:14 PM, Brad Love wrote: On 2018-01-16 13:32, Antti Palosaari wrote: On 01/16/2018 07:31 PM, Brad Love wrote: On 2018-01-15 23:07, Antti Palosaari wrote: Hello And what is rationale here, is there some use case demod must be active and ts set to tristate (disabled)? Just put demod sleep when you don't use it. regards Antti Hello Antti, Perhaps the .ts_bus_ctrl callback does not need to be included in ops, but the function is necessary. The demod is already put to sleep when not in use, but it leaves the ts bus open. The ts bus has no reason to be open when the demod is put to sleep. Leaving the ts bus open during sleep affects the other connected demod and nothing is received by it. The lgdt3306a driver already tri states its ts bus when put to sleep, the si2168 should as well. Sounds possible, but unlikely as chip is firmware driven. When you put chip to sleep you usually want set ts pins to tristate (also other unused pins) in order to save energy. I haven't never tested it anyway though, so it could be possible it leaves those pins to some other state like random output at given time. And if you cannot get stream from lgdt3306a, which is connected to same bus, it really sounds like ts bus pins are left some state (cannot work if same pin is driven high to other demod whilst other tries to drive it low. Setting ts pins to tri-state during sleep should resolve your issue. Hello Antti, This patch fixes the issue I'm describing, hence why I submitted it. The ts bus must be tristated before putting the chip to sleep for the other demod to get a stream. I can test tri-state using power meter on some day, but it may be so small current that it cannot be seen usb power meter I use (YZXstudio, very nice small power meter). regards Antti -- http://palosaari.fi/
Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
On 01/16/2018 07:31 PM, Brad Love wrote: On 2018-01-15 23:07, Antti Palosaari wrote: Hello And what is rationale here, is there some use case demod must be active and ts set to tristate (disabled)? Just put demod sleep when you don't use it. regards Antti Hello Antti, Perhaps the .ts_bus_ctrl callback does not need to be included in ops, but the function is necessary. The demod is already put to sleep when not in use, but it leaves the ts bus open. The ts bus has no reason to be open when the demod is put to sleep. Leaving the ts bus open during sleep affects the other connected demod and nothing is received by it. The lgdt3306a driver already tri states its ts bus when put to sleep, the si2168 should as well. Sounds possible, but unlikely as chip is firmware driven. When you put chip to sleep you usually want set ts pins to tristate (also other unused pins) in order to save energy. I haven't never tested it anyway though, so it could be possible it leaves those pins to some other state like random output at given time. And if you cannot get stream from lgdt3306a, which is connected to same bus, it really sounds like ts bus pins are left some state (cannot work if same pin is driven high to other demod whilst other tries to drive it low. Setting ts pins to tri-state during sleep should resolve your issue. regards Antti -- http://palosaari.fi/
Re: [PATCH 6/7] si2168: Announce frontend creation failure
hmmm, IIRC driver core even prints some error when driver probe fails? After that you could enable module debug logging to see more information. So I don't see point for that change. regards Antti On 01/12/2018 06:19 PM, Brad Love wrote: The driver outputs on success, but is silent on failure. Give one message that probe failed. Signed-off-by: Brad Love --- drivers/media/dvb-frontends/si2168.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 429c03a..c1a638c 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -810,7 +810,7 @@ static int si2168_probe(struct i2c_client *client, err_kfree: kfree(dev); err: - dev_dbg(&client->dev, "failed=%d\n", ret); + dev_warn(&client->dev, "probe failed = %d\n", ret); return ret; } -- http://palosaari.fi/
Re: [PATCH 4/7] si2168: Add ts bus coontrol, turn off bus on sleep
Hello And what is rationale here, is there some use case demod must be active and ts set to tristate (disabled)? Just put demod sleep when you don't use it. regards Antti On 01/12/2018 06:19 PM, Brad Love wrote: Includes a function to set TS MODE property os si2168. The function either disables the TS output bus, or sets mode to config option. When going to sleep the TS bus is turned off, this makes the driver compatible with multiple frontend usage. Signed-off-by: Brad Love --- drivers/media/dvb-frontends/si2168.c | 38 drivers/media/dvb-frontends/si2168.h | 1 + 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 539399d..429c03a 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -409,6 +409,30 @@ static int si2168_set_frontend(struct dvb_frontend *fe) return ret; } +static int si2168_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct i2c_client *client = fe->demodulator_priv; + struct si2168_dev *dev = i2c_get_clientdata(client); + struct si2168_cmd cmd; + int ret = 0; + + dev_dbg(&client->dev, "%s acquire: %d\n", __func__, acquire); + + /* set TS_MODE property */ + memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + if (acquire) + cmd.args[4] |= dev->ts_mode; + else + cmd.args[4] |= SI2168_TS_TRISTATE; + if (dev->ts_clock_gapped) + cmd.args[4] |= 0x40; + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(client, &cmd); + + return ret; +} + static int si2168_init(struct dvb_frontend *fe) { struct i2c_client *client = fe->demodulator_priv; @@ -540,14 +564,7 @@ static int si2168_init(struct dvb_frontend *fe) dev->version >> 24 & 0xff, dev->version >> 16 & 0xff, dev->version >> 8 & 0xff, dev->version >> 0 & 0xff); - /* set ts mode */ - memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); - cmd.args[4] |= dev->ts_mode; - if (dev->ts_clock_gapped) - cmd.args[4] |= 0x40; - cmd.wlen = 6; - cmd.rlen = 4; - ret = si2168_cmd_execute(client, &cmd); + ret = si2168_ts_bus_ctrl(fe, 1); if (ret) goto err; @@ -584,6 +601,9 @@ static int si2168_sleep(struct dvb_frontend *fe) dev->active = false; + /* tri-state data bus */ + si2168_ts_bus_ctrl(fe, 0); + /* Firmware B 4.0-11 or later loses warm state during sleep */ if (dev->version > ('B' << 24 | 4 << 16 | 0 << 8 | 11 << 0)) dev->warm = false; @@ -681,6 +701,8 @@ static const struct dvb_frontend_ops si2168_ops = { .init = si2168_init, .sleep = si2168_sleep, + .ts_bus_ctrl = si2168_ts_bus_ctrl, + .set_frontend = si2168_set_frontend, .read_status = si2168_read_status, diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 3225d0c..f48f0fb 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -38,6 +38,7 @@ struct si2168_config { /* TS mode */ #define SI2168_TS_PARALLEL0x06 #define SI2168_TS_SERIAL 0x03 +#define SI2168_TS_TRISTATE 0x00 u8 ts_mode; /* TS clock inverted */ -- http://palosaari.fi/
Re: [PATCH 3/7] si2157: Add hybrid tuner support
stance) { + case 0: + goto fail; + case 1: + /* new tuner instance */ + dev_dbg(&client->dev, "%s(): new instance for tuner @0x%02x\n", + __func__, addr); + dev->addr = addr; + i2c_set_clientdata(client, dev); + + dev->fe = fe; + dev->chiptype = SI2157_CHIPTYPE_SI2157; + dev->if_frequency = 0; + dev->if_port = cfg->if_port; + dev->inversion = cfg->inversion; + + mutex_init(&dev->i2c_mutex); + INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work); + + break; + default: + /* existing tuner instance */ + dev_dbg(&client->dev, + "%s(): using existing instance for tuner @0x%02x\n", +__func__, addr); + break; + } + + /* check if the tuner is there */ + cmd.wlen = 0; + cmd.rlen = 1; + ret = si2157_cmd_execute(client, &cmd); + /* verify no i2c error and CTS is set */ + if (ret) { + dev_warn(&client->dev, "no HW found ret=%d\n", ret); + goto fail_instance; + } + + memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops)); + +#ifdef CONFIG_MEDIA_CONTROLLER + if (instance == 1 && cfg->mdev) { + dev->mdev = cfg->mdev; + + dev->ent.name = KBUILD_MODNAME; + dev->ent.function = MEDIA_ENT_F_TUNER; + + dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK; + dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE; + dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS, +&dev->pad[0]); + + if (ret) + goto fail_instance; + + ret = media_device_register_entity(cfg->mdev, &dev->ent); + if (ret) { + dev_warn(&client->dev, + "media_device_regiser_entity returns %d\n", ret); + media_entity_cleanup(&dev->ent); + goto fail_instance; + } + } +#endif + mutex_unlock(&si2157_list_mutex); + + if (instance != 1) + dev_info(&client->dev, "Silicon Labs %s successfully attached\n", + dev->chiptype == SI2157_CHIPTYPE_SI2141 ? "Si2141" : + dev->chiptype == SI2157_CHIPTYPE_SI2146 ? + "Si2146" : "Si2147/2148/2157/2158"); + + return fe; +fail_instance: + mutex_unlock(&si2157_list_mutex); + + si2157_release(fe); +fail: + dev_warn(&client->dev, "Attach failed\n"); + return NULL; +} +EXPORT_SYMBOL(si2157_attach); + +MODULE_DESCRIPTION("Silicon Labs Si2141/2146/2147/2148/2157/2158 silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari "); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(SI2158_A20_FIRMWARE); diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h index de597fa..26b94ca 100644 --- a/drivers/media/tuners/si2157.h +++ b/drivers/media/tuners/si2157.h @@ -46,4 +46,18 @@ struct si2157_config { u8 if_port; }; +#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SI2157) +extern struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c, + struct si2157_config *cfg); +#else +static inline struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, + u8 addr, + struct i2c_adapter *i2c, + struct si2157_config *cfg) +{ + pr_err("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif #endif diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index e6436f7..2801aaa 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -19,15 +19,20 @@ #include #include +#include "tuner-i2c.h" #include "si2157.h" /* state struct */ struct si2157_dev { + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + struct mutex i2c_mutex; struct dvb_frontend *fe; bool active; bool inversion; u8 chiptype; + u8 addr; u8 if_port; u32 if_frequency; struct delayed_work stat_work; -- http://palosaari.fi/
Re: [PATCH] [media] tda18212: fix use-after-free in tda18212_remove()
On 12/15/2017 08:40 PM, Daniel Scheller wrote: On Fri, 15 Dec 2017 20:12:18 +0200 Antti Palosaari wrote: On 12/15/2017 08:00 PM, Daniel Scheller wrote: Hi, On Fri, 15 Dec 2017 19:30:18 +0200 Antti Palosaari wrote: Thanks for your reply. Hello I think shared frontend structure, which is owned by demod driver, should be there and valid on time tuner driver is removed. And thus should not happen. Did you make driver unload on different order eg. not just reverse order than driver load? IMHO these should go always on load: 1) load demod driver (which makes shared frontend structure where also some tuner driver data lives) 2) load tuner driver 3) register frontend on unload 1) unregister frontend 2) remove tuner driver 3) remove demod driver (frees shared data) In ddbridge, we do (like in usb/em28xx and platform/sti/c8sectpfe, both also use some demod+tda18212 combo): dvb_unregister_frontend(); dvb_frontend_detach(); module_put(tda18212client->...owner); i2c_unregister_device(tda18212client); fe_detach() clears out the frontend references and frees/invalidates the allocated resources. tuner_ops obviously isn't there then anymore. yeah, but that's even ideally wrong. frontend design currently relies to shared data which is owned by demod driver and thus it should be last thing to be removed. Sure change like you did prevents issue, but logically it is still wrong and may not work on some other case. The two mentioned drivers will very likely yield the same (or similar) KASAN report. em28xx was even changed lately to do the teardown the way ddbridge does in 910b0797fa9e8 ([1], cc'ing Matthias here). With that commit in mind I'm a bit unsure on what is correct or not. OTOH, as dvb_frontend_detach() cleans up everything, IMHO there's no need for the tuner driver to try to clean up further. Please advise. [1] https://git.linuxtv.org/media_tree.git/commit/?id=910b0797fa9e8. em28xx does it currently just correct. 1) unregister frontend Note that this is a call to em28xx_unregister_dvb(), which in turn does dvb_unregister_frontend() and then dvb_frontend_detach() (at this stage, fe resources are gone). 2) remove I2C SEC 3) remove I2C tuner 4) remove I2C demod (frees shared frontend data) Yes, but ie. EM2874_BOARD_KWORLD_UB435Q_V3 is a combination of a "legacy" demod frontend - lgdt3305 actually - plus the tda18212 i2cclient (just like in ddb with stv0367+tda18212 or cxd2841er+tda18212), I'm sure this will yield the same report. Maybe another approach: Implement the tuner_ops.release callback, and then move the memset+NULL assignment right there (instead of just removing it), but this likely will cause issues when the i2c client is removed before detach if we don't keep track of this ie somewhere in tda18212_dev (new state var - if _remove is called, check if the tuner was released, and if not, call release (memset/set NULL), then free). Still with the two other drivers in mind though. If they're wrong aswell, I'll rather fix up ddbridge of course. Whole memset thing could be removed from tda18212, there is something likely wrong if those are needed. But it is another issue. Your main issue is somehow to get order of demod/tuner destroy correct. I don't even like idea whole shared frontend data is owned by the demod driver instance, but currently it is there and due to that this should be released lastly. General design goal is also do things like register things in order and unregister just reverse-order. regards Antti -- http://palosaari.fi/
Re: [PATCH] [media] tda18212: fix use-after-free in tda18212_remove()
On 12/15/2017 08:00 PM, Daniel Scheller wrote: Hi, On Fri, 15 Dec 2017 19:30:18 +0200 Antti Palosaari wrote: Thanks for your reply. Hello I think shared frontend structure, which is owned by demod driver, should be there and valid on time tuner driver is removed. And thus should not happen. Did you make driver unload on different order eg. not just reverse order than driver load? IMHO these should go always on load: 1) load demod driver (which makes shared frontend structure where also some tuner driver data lives) 2) load tuner driver 3) register frontend on unload 1) unregister frontend 2) remove tuner driver 3) remove demod driver (frees shared data) In ddbridge, we do (like in usb/em28xx and platform/sti/c8sectpfe, both also use some demod+tda18212 combo): dvb_unregister_frontend(); dvb_frontend_detach(); module_put(tda18212client->...owner); i2c_unregister_device(tda18212client); fe_detach() clears out the frontend references and frees/invalidates the allocated resources. tuner_ops obviously isn't there then anymore. yeah, but that's even ideally wrong. frontend design currently relies to shared data which is owned by demod driver and thus it should be last thing to be removed. Sure change like you did prevents issue, but logically it is still wrong and may not work on some other case. The two mentioned drivers will very likely yield the same (or similar) KASAN report. em28xx was even changed lately to do the teardown the way ddbridge does in 910b0797fa9e8 ([1], cc'ing Matthias here). With that commit in mind I'm a bit unsure on what is correct or not. OTOH, as dvb_frontend_detach() cleans up everything, IMHO there's no need for the tuner driver to try to clean up further. Please advise. [1] https://git.linuxtv.org/media_tree.git/commit/?id=910b0797fa9e8. em28xx does it currently just correct. 1) unregister frontend 2) remove I2C SEC 3) remove I2C tuner 4) remove I2C demod (frees shared frontend data) regards Antti -- http://palosaari.fi/
Re: [PATCH] [media] tda18212: fix use-after-free in tda18212_remove()
ridge] [ 154.028695] ddb_remove+0x3c/0xb0 [ddbridge] [ 154.028697] pci_device_remove+0x93/0x1d0 [ 154.028700] device_release_driver_internal+0x267/0x510 [ 154.028702] driver_detach+0xb9/0x1b0 [ 154.028705] bus_remove_driver+0xd0/0x1f0 [ 154.028707] pci_unregister_driver+0x25/0x210 [ 154.028711] module_exit_ddbridge+0xc/0x45 [ddbridge] [ 154.028714] SyS_delete_module+0x314/0x440 [ 154.028716] do_syscall_64+0x179/0x4c0 [ 154.028718] return_from_SYSCALL_64+0x0/0x65 [ 154.028729] The buggy address belongs to the object at 880108b55340 which belongs to the cache kmalloc-2048 of size 2048 [ 154.028755] The buggy address is located 408 bytes inside of 2048-byte region [880108b55340, 880108b55b40) [ 154.028778] The buggy address belongs to the page: [ 154.028792] page:ea00039e7a60 count:1 mapcount:0 mapping:880108b54240 index:0x0 compound_mapcount: 0 [ 154.028814] flags: 0x80008100(slab|head) [ 154.028830] raw: 80008100 880108b54240 00010003 [ 154.028848] raw: ea00039e7310 ea00039e7bd0 88010b000800 [ 154.028862] page dumped because: kasan: bad access detected [ 154.028883] Memory state around the buggy address: [ 154.028896] 880108b55380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028913] 880108b55400: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028929] >880108b55480: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028945] ^ [ 154.028960] 880108b55500: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028976] 880108b55580: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 154.028991] == [ 154.029006] Disabling lock debugging due to kernel taint Fix this by removing the memcpy and the NULL assign. Cc: Antti Palosaari Signed-off-by: Daniel Scheller --- drivers/media/tuners/tda18212.c | 5 - 1 file changed, 5 deletions(-) diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c index 7b8068354fea..ebccf8a8729d 100644 --- a/drivers/media/tuners/tda18212.c +++ b/drivers/media/tuners/tda18212.c @@ -258,12 +258,7 @@ static int tda18212_probe(struct i2c_client *client, static int tda18212_remove(struct i2c_client *client) { struct tda18212_dev *dev = i2c_get_clientdata(client); - struct dvb_frontend *fe = dev->cfg.fe; - dev_dbg(&client->dev, "\n"); - - memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = NULL; kfree(dev); return 0; -- http://palosaari.fi/
Re: rc-core: how to use hid (hardware) decoder?
On 07/15/2017 12:05 PM, Sean Young wrote: Hello, On Fri, Jul 14, 2017 at 04:14:05AM +0300, Antti Palosaari wrote: Moikka! Some remote controller receivers uses HID interface. I looked rc-core implementation, but failed to find how it could be used for hid. I need somehow get scancodes and keycodes out from rc-core and write those to hardware which then generate hid events. Also, I am not sure if kernel keycodes are same than HID codes, but if not then those should be translated somehow. There is rc_g_keycode_from_table() function, which could be used to dump current scancode:keycode mapping, but calling it in a loop millions of times is not surely correctly :] Possibly you could use rc_map_get() to get the entire array. However you would be limited to rc keymaps which are compiled into the kernel. It be good to expose an interface to userspace which allows you to read and write the mapping from IR protocol + scancode to hid usage codes; you could then have an ir-keytable-like tool to change the keymap. That was just the plan. I added callback to ir_update_mapping() in order to get info and new rc_map every-time when it was changed. Then driver configures hid table accordingly. I ran some issues: * HID has very limited set of keys used for remote controllers compared to linux. So mapping from Linux remote controller to HID went hard. * NEC 16/24/32 mess. rc_map used by rc-core was typed as NEC16, even there was NEC24 scancodes. So more self-made heuristics as hw wants NEC32. So I given it up. I can configure that remote both polling mode via rc-core and HID. rc-core gives much more flexibility, mainly due to limited keymap of HID (hw supports only HID page 7, keyboard). regards Antti -- http://palosaari.fi/
rc-core: how to use hid (hardware) decoder?
Moikka! Some remote controller receivers uses HID interface. I looked rc-core implementation, but failed to find how it could be used for hid. I need somehow get scancodes and keycodes out from rc-core and write those to hardware which then generate hid events. Also, I am not sure if kernel keycodes are same than HID codes, but if not then those should be translated somehow. There is rc_g_keycode_from_table() function, which could be used to dump current scancode:keycode mapping, but calling it in a loop millions of times is not surely correctly :] Any ideas? regards Antti -- http://palosaari.fi/
Re: [PATCH V2 4/9] [media] dvb-core/dvb_ca_en50221.c: Fixed block comments
On 07/13/2017 03:04 AM, Antti Palosaari wrote: On 07/13/2017 02:45 AM, Jasmin J. wrote: Hello Antti! Have you ever looked that coding style doc? Yes I read it several times already and used it in my daily work in my previous company. Beside the Multi-line comment style, which I will fix in a follow up, you mentioned other issues. Please can you tell me which one you mean, so that I can check the series for those things. eh, OK, here short list from my head: * you fixed comments, but left //-comments * many cases where if (ret != 0), which generally should be written as if (ret). If you expect it is just error ret value, then prefer if (ret), but if ret has some other meaning like it returns number of bytes then if you expect 0-bytes returned (ret != 0) is also valid. * unnecessary looking line split like that: if (a & b) * logical continuous line split wrong (I think I have seen checkpatch reported that kind of mistakes, dunno why not now) if (a && b) == > if (a && b) actually it reports, when run --strict mode: + if (a + && b) { + foo(a); + foo(b); + } + CHECK: Logical continuations should be on the previous line #11: FILE: drivers/media/usb/dvb-usb-v2/af9035.c:2135: + if (a + && b) { Antti -- http://palosaari.fi/
Re: [PATCH V2 4/9] [media] dvb-core/dvb_ca_en50221.c: Fixed block comments
On 07/13/2017 02:45 AM, Jasmin J. wrote: Hello Antti! Have you ever looked that coding style doc? Yes I read it several times already and used it in my daily work in my previous company. Beside the Multi-line comment style, which I will fix in a follow up, you mentioned other issues. Please can you tell me which one you mean, so that I can check the series for those things. eh, OK, here short list from my head: * you fixed comments, but left //-comments * many cases where if (ret != 0), which generally should be written as if (ret). If you expect it is just error ret value, then prefer if (ret), but if ret has some other meaning like it returns number of bytes then if you expect 0-bytes returned (ret != 0) is also valid. * unnecessary looking line split like that: if (a & b) * logical continuous line split wrong (I think I have seen checkpatch reported that kind of mistakes, dunno why not now) if (a && b) == > if (a && b) Antti -- http://palosaari.fi/
Re: [PATCH V2 4/9] [media] dvb-core/dvb_ca_en50221.c: Fixed block comments
On 07/13/2017 02:23 AM, Jasmin J. wrote: Hello Antti! Quickly looking this patch serie I noticed few other coding style mistakes. You should read kernel coding style documentation first, and then make changes according to doc. In fact I used checkpatch.pl to find the issues and fixed them. All the patches are 100% checkpatch.pl tested and did not have one single error or warning. So please can you point me to those issues you mean. Have you ever looked that coding style doc? Maybe better to start reading it first. Checkpatch is only a tool, it is nothing which makes 100% decision which is correct or not. Multi-line comment style is explained on section 8 on kernel coding style doc. Antti -- http://palosaari.fi/
Re: [PATCH] Added support for the TerraTec T1 DVB-T USB tuner [IT9135 chipset]
On 06/29/2017 08:55 PM, Nuno Henriques wrote: Signed-off-by: Nuno Henriques --- drivers/media/dvb-core/dvb-usb-ids.h | 1 + drivers/media/usb/dvb-usb-v2/af9035.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index e200aa6f2d2f..5b6041d462bc 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -279,6 +279,7 @@ #define USB_PID_TERRATEC_H7 0x10b4 #define USB_PID_TERRATEC_H7_2 0x10a3 #define USB_PID_TERRATEC_H7_3 0x10a5 +#define USB_PID_TERRATEC_T10x10ae #define USB_PID_TERRATEC_T3 0x10a0 #define USB_PID_TERRATEC_T5 0x10a1 #define USB_PID_NOXON_DAB_STICK 0x00b3 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 4df9486e19b9..ccf4a5c68877 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -2108,6 +2108,8 @@ static const struct usb_device_id af9035_id_table[] = { { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2, &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2", RC_MAP_IT913X_V1) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T1, + &af9035_props, "TerraTec T1", RC_MAP_IT913X_V1) }, /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099, &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", Does this stick has a remote? I see always red when I see someone adds RC_MAP_IT913X_V1 remote controller as there is now too many simply totally wrongly defined remote controllers on that driver. Commit message is missing, even it is very trivial patch there should be something like It is IT9135BX device having USB ID : and remote controller model is x.. Use git log to see other commit messages where new usb id is added. regards Antti -- http://palosaari.fi/
Re: [PATCH V2 4/9] [media] dvb-core/dvb_ca_en50221.c: Fixed block comments
On 07/13/2017 02:00 AM, Jasmin J. wrote: From: Jasmin Jessich Fixed all: WARNING: Block comments use * on subsequent lines Also multiline comments should be written like this: /* * Comment. */ Quickly looking this patch serie I noticed few other coding style mistakes. You should read kernel coding style documentation first, and then make changes according to doc. regards Antti -- http://palosaari.fi/
Re: [PATCH 3/4] [media] dvb-frontends/stv0367: SNR DVBv5 statistics for DVB-C and T
On 06/21/2017 06:50 PM, Daniel Scheller wrote: Am Wed, 21 Jun 2017 09:30:27 +0300 schrieb Antti Palosaari : On 06/20/2017 08:45 PM, Daniel Scheller wrote: From: Daniel Scheller Add signal-to-noise-ratio as provided by the demodulator in decibel scale. QAM/DVB-C needs some intlog calculation to have usable dB values, OFDM/ DVB-T values from the demod look alright already and are provided as-is. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 33 + 1 file changed, 33 insertions(+) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index bb498f942ebd..0b13a407df23 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -25,6 +25,8 @@ #include #include +#include "dvb_math.h" + #include "stv0367.h" #include "stv0367_defs.h" #include "stv0367_regs.h" @@ -33,6 +35,9 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 +/* snr logarithmic calc */ +#define INTLOG10X100(x) ((u32) (((u64) intlog10(x) * 100) >> 24)) + static int stvdebug; module_param_named(debug, stvdebug, int, 0644); @@ -3013,6 +3018,33 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, return -EINVAL; } +static void stv0367ddb_read_snr(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int cab_pwr; + u32 regval, tmpval, snrval = 0; + + switch (state->activedemod) { + case demod_ter: + snrval = stv0367ter_snr_readreg(fe); + break; + case demod_cab: + cab_pwr = stv0367cab_snr_power(fe); + regval = stv0367cab_snr_readreg(fe, 0); + + tmpval = (cab_pwr * 320) / regval; + snrval = ((tmpval != 0) ? INTLOG10X100(tmpval) : 0) * 100; How much there will be rounding errors due to that signal/noise division? I would convert it to calculation of sums (tip logarithm calculation rules). This is taken from stv0367dd aswell, the reported and calculated values are in 0.1dB precision. This and to not diverge any more from the "source" driver, I'd prefer to keep it how it is. These are just simple tuner cards anyway and by no means professional measurement gear, and should only give a more or less rough estimate on reception quality. E.g. my stv0367 cards report around 36dB SNR, whereas the cxd2841er reports ~37dB, compared to my DOCSIS modem, which reports 34dB on DOCSIS channels (another variant I had earlier even reported 39dB on the same channels), so... Even, we get way more precision than on the relative scale calc on the cab_read_snr functions which is in 10%-steps... Also, that INTLOG10X100 is pretty much useless. Use just what intlog10/intlog2 offers without yet again another conversion. Will check and experiment. Again, taken from stv0367dd :-) You should understand that there is no floating points on kernel, thus that kind of divisions needs special attention. It should be written log10(signal) - log10(noise) in order to minimize rounding errors. Lets say as example if you divide 2 by 3 you will get 0, not 0.666... So depending on actual numbers used on calculation, there is more or less rounding errors which are easily avoidable. Antti -- http://palosaari.fi/
Re: [PATCH] [media] ddbridge: use dev_* macros in favor of printk
On 06/21/2017 08:20 PM, Mauro Carvalho Chehab wrote: Em Wed, 21 Jun 2017 19:14:40 +0200 Daniel Scheller escreveu: Am Wed, 21 Jun 2017 14:08:08 -0300 schrieb Mauro Carvalho Chehab : Em Wed, 21 Jun 2017 18:53:47 +0200 Daniel Scheller escreveu: From: Daniel Scheller Side effect: KERN_DEBUG messages aren't written to the kernel log anymore. This also improves the tda18212_ping reporting a bit so users know that if pinging wasn't successful, bad things will happen. Since in module_init_ddbridge() there's no dev yet, pr_info is used instead. Signed-off-by: Daniel Scheller --- drivers/media/pci/ddbridge/ddbridge-core.c | 78 ++ 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 9420479bee9a..540a121eadd6 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -17,6 +17,8 @@ * http://www.gnu.org/copyleft/gpl.html */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + I guess this is a left over from the old patch. When you use dev_foo, it will get the driver's name from dev->name. So, no need to do the above. I intentionally left this in for the pr_info used in module_init_ddbridge(). If you prefer, we can ofc probably also leave this as printk like printk(KERN_INFO KBUILD_MODNAME ": Digital..."); Ah, OK! But why you even need it? Probe should be first place you need to print something and there is always proper device pointer. Antti -- http://palosaari.fi/
Re: [PATCH 3/4] [media] dvb-frontends/stv0367: SNR DVBv5 statistics for DVB-C and T
On 06/20/2017 08:45 PM, Daniel Scheller wrote: From: Daniel Scheller Add signal-to-noise-ratio as provided by the demodulator in decibel scale. QAM/DVB-C needs some intlog calculation to have usable dB values, OFDM/ DVB-T values from the demod look alright already and are provided as-is. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 33 + 1 file changed, 33 insertions(+) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index bb498f942ebd..0b13a407df23 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -25,6 +25,8 @@ #include #include +#include "dvb_math.h" + #include "stv0367.h" #include "stv0367_defs.h" #include "stv0367_regs.h" @@ -33,6 +35,9 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 +/* snr logarithmic calc */ +#define INTLOG10X100(x) ((u32) (((u64) intlog10(x) * 100) >> 24)) + static int stvdebug; module_param_named(debug, stvdebug, int, 0644); @@ -3013,6 +3018,33 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, return -EINVAL; } +static void stv0367ddb_read_snr(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int cab_pwr; + u32 regval, tmpval, snrval = 0; + + switch (state->activedemod) { + case demod_ter: + snrval = stv0367ter_snr_readreg(fe); + break; + case demod_cab: + cab_pwr = stv0367cab_snr_power(fe); + regval = stv0367cab_snr_readreg(fe, 0); + + tmpval = (cab_pwr * 320) / regval; + snrval = ((tmpval != 0) ? INTLOG10X100(tmpval) : 0) * 100; How much there will be rounding errors due to that signal/noise division? I would convert it to calculation of sums (tip logarithm calculation rules). Also, that INTLOG10X100 is pretty much useless. Use just what intlog10/intlog2 offers without yet again another conversion. + break; + default: + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; + p->cnr.stat[0].uvalue = snrval; +} + static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; @@ -3069,6 +3101,7 @@ static int stv0367ddb_get_frontend(struct dvb_frontend *fe, } stv0367ddb_read_ucblocks(fe); + stv0367ddb_read_snr(fe); return 0; } regards Antti -- http://palosaari.fi/
Re: [PATCH 1/4] [media] dvb-frontends/stv0367: initial DDB DVBv5 stats, implement ucblocks
On 06/20/2017 08:45 PM, Daniel Scheller wrote: From: Daniel Scheller This adds the basics to stv0367ddb_get_frontend() to be able to properly provide signal statistics in DVBv5 format. Also adds UCB readout and provides those values. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 59 --- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index e726c2e00460..5374d4eaabd6 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -2997,21 +2997,64 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, return -EINVAL; } +static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 ucblocks = 0; + + switch (state->activedemod) { + case demod_ter: + stv0367ter_read_ucblocks(fe, &ucblocks); + break; + case demod_cab: + stv0367cab_read_ucblcks(fe, &ucblocks); + break; + default: + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->block_error.stat[0].scale = FE_SCALE_COUNTER; + p->block_error.stat[0].uvalue = ucblocks; +} + static int stv0367ddb_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p) { struct stv0367_state *state = fe->demodulator_priv; + int ret = -EINVAL; + enum fe_status status = 0; switch (state->activedemod) { case demod_ter: - return stv0367ter_get_frontend(fe, p); + ret = stv0367ter_get_frontend(fe, p); + break; case demod_cab: - return stv0367cab_get_frontend(fe, p); - default: + ret = stv0367cab_get_frontend(fe, p); break; + default: + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return ret; } - return -EINVAL; + /* read fe lock status */ + if (!ret) + ret = stv0367ddb_read_status(fe, &status); + + /* stop if get_frontend failed or if demod isn't locked */ + if (ret || !(status & FE_HAS_LOCK)) { + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return ret; + } Requiring LOCK for strength and cnr sounds wrong. Demod usually calculates strength from IF and RF AGC and those are available even there is no signal at all (demod set those gains to max on that case). CNR is pretty often available when inner FEC (viterbi, LDPC) is on sync. And for ber and per you need outer fec (reed-solomon, bch) too which is FE_HAS_SYNC flag on api. ber is error bit and count after inner fec, per is error packet and count after outer fec. Usually ber is counted as a bits and per is counted as a 204 ts packets. Also having that statistics stuff updated inside a get_frontend() sounds wrong. I think that callback is optional and is not called unless userspace polls it. + + stv0367ddb_read_ucblocks(fe); + + return 0; } static int stv0367ddb_sleep(struct dvb_frontend *fe) @@ -3035,6 +3078,7 @@ static int stv0367ddb_sleep(struct dvb_frontend *fe) static int stv0367ddb_init(struct stv0367_state *state) { struct stv0367ter_state *ter_state = state->ter_state; + struct dtv_frontend_properties *p = &state->fe.dtv_property_cache; stv0367_writereg(state, R367TER_TOPCTRL, 0x10); @@ -3109,6 +3153,13 @@ static int stv0367ddb_init(struct stv0367_state *state) ter_state->first_lock = 0; ter_state->unlock_counter = 2; + p->strength.len = 1; + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.len = 1; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.len = 1; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return 0; } regards Antti -- http://palosaari.fi/
Re: [PATCH] [media] ddbridge: use pr_* macros in favor of printk
On 06/20/2017 08:44 PM, Daniel Scheller wrote: From: Daniel Scheller Side effect: KERN_DEBUG messages aren't written to the kernel log anymore. This also improves the tda18212_ping reporting a bit so users know that if pinging wasn't successful, bad things might happen. It is device, not library, thus you should really use dev_ logging instead. With dev_ logging system could print better info, bus id etc. regards Antti -- http://palosaari.fi/
[GIT PULL 4.13] af9015/af9013 changes
The following changes since commit 3622d3e77ecef090b5111e3c5423313f11711dfa: [media] ov2640: print error if devm_*_optional*() fails (2017-04-25 07:08:21 -0300) are available in the git repository at: git://linuxtv.org/anttip/media_tree.git af9015_pull for you to fetch changes up to 2a32db020ab01e3ac99febad90a42112aa28b2ee: af9013: refactor power control (2017-06-18 05:42:25 +0300) Antti Palosaari (15): af9015: use correct 7-bit i2c addresses af9013: move config values directly under driver state af9013: add i2c client bindings af9013: use kernel 64-bit division af9013: fix logging af9013: convert to regmap api af9013: fix error handling af9013: add dvbv5 cnr af9015: fix and refactor i2c adapter algo logic af9015: enable 2nd TS flow control when dual mode af9013: add configurable TS output pin af9013: remove unneeded register writes af9015: move 2nd demod power-up wait different location af9013: refactor firmware download routine af9013: refactor power control Gustavo A. R. Silva (1): af9013: add check on af9013_wr_regs() return value drivers/media/dvb-frontends/Kconfig |1 + drivers/media/dvb-frontends/af9013.c | 1185 ++- drivers/media/dvb-frontends/af9013.h | 86 +-- drivers/media/dvb-frontends/af9013_priv.h |2 + drivers/media/usb/dvb-usb-v2/af9015.c | 198 +--- drivers/media/usb/dvb-usb-v2/af9015.h |4 +- 6 files changed, 752 insertions(+), 724 deletions(-) -- http://palosaari.fi/
[PATCH 11/15] af9013: add configurable TS output pin
On serial TS mode output pin could be selected from D0 or D7. Add configuration option to for it. Rename TS mode config option prefix from AF9013_TS_ to AF9013_TS_MODE_. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 27 ++- drivers/media/dvb-frontends/af9013.h | 2 ++ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 68091f2..6b86437 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -28,6 +28,7 @@ struct af9013_state { u8 tuner; u32 if_frequency; u8 ts_mode; + u8 ts_output_pin; bool spec_inv; u8 api_version[4]; u8 gpio[4]; @@ -955,17 +956,12 @@ static int af9013_init(struct dvb_frontend *fe) goto err; /* settings for mp2if */ - if (state->ts_mode == AF9013_TS_USB) { + if (state->ts_mode == AF9013_TS_MODE_USB) { /* AF9015 split PSB to 1.5k + 0.5k */ ret = regmap_update_bits(state->regmap, 0xd50b, 0x04, 0x04); if (ret) goto err; } else { - /* AF9013 change the output bit to data7 */ - ret = regmap_update_bits(state->regmap, 0xd500, 0x08, 0x08); - if (ret) - goto err; - /* AF9013 set mpeg to full speed */ ret = regmap_update_bits(state->regmap, 0xd502, 0x10, 0x10); if (ret) @@ -1046,9 +1042,12 @@ static int af9013_init(struct dvb_frontend *fe) goto err; } - /* TS mode */ - ret = regmap_update_bits(state->regmap, 0xd500, 0x06, -state->ts_mode << 1); + /* TS interface */ + if (state->ts_output_pin == 7) + utmp = 1 << 3 | state->ts_mode << 1; + else + utmp = 0 << 3 | state->ts_mode << 1; + ret = regmap_update_bits(state->regmap, 0xd500, 0x0e, utmp); if (ret) goto err; @@ -1147,7 +1146,7 @@ static int af9013_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) if (state->i2c_gate_state == enable) return 0; - if (state->ts_mode == AF9013_TS_USB) + if (state->ts_mode == AF9013_TS_MODE_USB) ret = regmap_update_bits(state->regmap, 0xd417, 0x08, enable << 3); else @@ -1297,6 +1296,7 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config, pdata.tuner = config->tuner; pdata.if_frequency = config->if_frequency; pdata.ts_mode = config->ts_mode; + pdata.ts_output_pin = 7; pdata.spec_inv = config->spec_inv; memcpy(&pdata.api_version, config->api_version, sizeof(pdata.api_version)); memcpy(&pdata.gpio, config->gpio, sizeof(pdata.gpio)); @@ -1450,7 +1450,7 @@ static int af9013_regmap_write(void *context, const void *data, size_t count) u8 *val = &((u8 *)data)[2]; const unsigned int len = count - 2; - if (state->ts_mode == AF9013_TS_USB && (reg & 0xff00) != 0xae00) { + if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|1 << 0; ret = af9013_wregs(client, cmd, reg, val, len); if (ret) @@ -1487,7 +1487,7 @@ static int af9013_regmap_read(void *context, const void *reg_buf, u8 *val = &((u8 *)val_buf)[0]; const unsigned int len = val_size; - if (state->ts_mode == AF9013_TS_USB && (reg & 0xff00) != 0xae00) { + if (state->ts_mode == AF9013_TS_MODE_USB && (reg & 0xff00) != 0xae00) { cmd = 0 << 7|0 << 6|(len - 1) << 2|1 << 1|0 << 0; ret = af9013_rregs(client, cmd, reg, val_buf, len); if (ret) @@ -1537,6 +1537,7 @@ static int af9013_probe(struct i2c_client *client, state->tuner = pdata->tuner; state->if_frequency = pdata->if_frequency; state->ts_mode = pdata->ts_mode; + state->ts_output_pin = pdata->ts_output_pin; state->spec_inv = pdata->spec_inv; memcpy(&state->api_version, pdata->api_version, sizeof(state->api_version)); memcpy(&state->gpio, pdata->gpio, sizeof(state->gpio)); @@ -1549,7 +1550,7 @@ static int af9013_probe(struct i2c_client *client, } /* Download firmware */ - if (state->ts_mode != AF9013_TS_USB) { + if (state->ts_mode != AF9013_TS_MODE_USB) { ret = af9013_download_firmware(state); if (ret)
[PATCH 03/15] af9013: add i2c client bindings
Add kernel i2c driver bindings. That allows dev_* logging, regmap and more. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 321 ++- drivers/media/dvb-frontends/af9013.h | 84 + 2 files changed, 241 insertions(+), 164 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 7880a63..f644182 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -24,9 +24,8 @@ #define MAX_XFER_SIZE 64 struct af9013_state { - struct i2c_adapter *i2c; + struct i2c_client *client; struct dvb_frontend fe; - u8 i2c_addr; u32 clk; u8 tuner; u32 if_frequency; @@ -59,7 +58,7 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = priv->i2c_addr, + .addr = priv->client->addr, .flags = 0, .len = 3 + len, .buf = buf, @@ -67,7 +66,7 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, }; if (3 + len > sizeof(buf)) { - dev_warn(&priv->i2c->dev, + dev_warn(&priv->client->dev, "%s: i2c wr reg=%04x: len=%d is too big!\n", KBUILD_MODNAME, reg, len); return -EINVAL; @@ -78,11 +77,11 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, buf[2] = mbox; memcpy(&buf[3], val, len); - ret = i2c_transfer(priv->i2c, msg, 1); + ret = i2c_transfer(priv->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%04x " \ + dev_warn(&priv->client->dev, "%s: i2c wr failed=%d reg=%04x " \ "len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } @@ -97,12 +96,12 @@ static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, u8 buf[3]; struct i2c_msg msg[2] = { { - .addr = priv->i2c_addr, + .addr = priv->client->addr, .flags = 0, .len = 3, .buf = buf, }, { - .addr = priv->i2c_addr, + .addr = priv->client->addr, .flags = I2C_M_RD, .len = len, .buf = val, @@ -113,11 +112,11 @@ static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, buf[1] = (reg >> 0) & 0xff; buf[2] = mbox; - ret = i2c_transfer(priv->i2c, msg, 2); + ret = i2c_transfer(priv->client->adapter, msg, 2); if (ret == 2) { ret = 0; } else { - dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%04x " \ + dev_warn(&priv->client->dev, "%s: i2c rd failed=%d reg=%04x " \ "len=%d\n", KBUILD_MODNAME, ret, reg, len); ret = -EREMOTEIO; } @@ -231,7 +230,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) u8 pos; u16 addr; - dev_dbg(&state->i2c->dev, "%s: gpio=%d gpioval=%02x\n", + dev_dbg(&state->client->dev, "%s: gpio=%d gpioval=%02x\n", __func__, gpio, gpioval); /* @@ -250,7 +249,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) break; default: - dev_err(&state->i2c->dev, "%s: invalid gpio=%d\n", + dev_err(&state->client->dev, "%s: invalid gpio=%d\n", KBUILD_MODNAME, gpio); ret = -EINVAL; goto err; @@ -274,7 +273,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) return ret; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&state->client->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -282,7 +281,7 @@ static u32 af9013_div(struct af9013_state *state, u32 a, u32 b, u32 x) { u32 r = 0, c = 0, i; - dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); + dev_dbg(&state->client->dev, "%s: a=%d b=%d x=%
[PATCH 10/15] af9015: enable 2nd TS flow control when dual mode
It needs to be enabled in order to get stream from slave af9013 demod. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 15 +-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 54c1d47..ee0e354 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -1131,10 +1131,21 @@ static int af9015_init_endpoint(struct dvb_usb_device *d) } /* enable / disable mp2if2 */ - if (state->dual_mode) + if (state->dual_mode) { ret = af9015_set_reg_bit(d, 0xd50b, 0); - else + if (ret) + goto error; + ret = af9015_set_reg_bit(d, 0xd520, 4); + if (ret) + goto error; + } else { ret = af9015_clear_reg_bit(d, 0xd50b, 0); + if (ret) + goto error; + ret = af9015_clear_reg_bit(d, 0xd520, 4); + if (ret) + goto error; + } error: if (ret) -- http://palosaari.fi/
[PATCH 07/15] af9013: fix error handling
Use typical (return 0/goto err/return err) error handling everywhere. Add missing error handling where missing. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 86 +--- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 70102c1..a6b88ae 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -94,7 +94,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) if (ret) goto err; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -147,7 +147,7 @@ static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) goto err; } - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -166,7 +166,7 @@ static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe) if (ret) goto err; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -199,7 +199,7 @@ static int af9013_statistics_ber_unc_result(struct dvb_frontend *fe) state->ber = (buf[2] << 16) | (buf[1] << 8) | buf[0]; state->ucblocks += (buf[4] << 8) | buf[3]; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -218,7 +218,7 @@ static int af9013_statistics_snr_start(struct dvb_frontend *fe) if (ret) goto err; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -283,7 +283,7 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) } state->snr = utmp * 10; /* dB/10 */ - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -321,7 +321,7 @@ static int af9013_statistics_signal_strength(struct dvb_frontend *fe) state->signal_strength = signal_strength; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -398,8 +398,11 @@ static int af9013_set_frontend(struct dvb_frontend *fe) c->frequency, c->bandwidth_hz); /* program tuner */ - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe); + if (fe->ops.tuner_ops.set_params) { + ret = fe->ops.tuner_ops.set_params(fe); + if (ret) + goto err; + } /* program CFOE coefficients */ if (c->bandwidth_hz != state->bandwidth_hz) { @@ -411,20 +414,28 @@ static int af9013_set_frontend(struct dvb_frontend *fe) } /* Return an error if can't find bandwidth or the right clock */ - if (i == ARRAY_SIZE(coeff_lut)) - return -EINVAL; + if (i == ARRAY_SIZE(coeff_lut)) { + ret = -EINVAL; + goto err; + } ret = regmap_bulk_write(state->regmap, 0xae00, coeff_lut[i].val, sizeof(coeff_lut[i].val)); + if (ret) + goto err; } /* program frequency control */ if (c->bandwidth_hz != state->bandwidth_hz || state->first_tune) { /* get used IF frequency */ - if (fe->ops.tuner_ops.get_if_frequency) - fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); - else + if (fe->ops.tuner_ops.get_if_frequency) { + ret = fe->ops.tuner_ops.get_if_frequency(fe, +&if_frequency); + if (ret) + goto err; + } else { if_frequency = state->if_frequency; + } dev_dbg(&client->dev, "if_frequency %u\n", if_frequency); @@ -659,7 +670,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) state->set_frontend_jiffies = jiffies; state->first_tune = false; - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; @@ -777,7 +788,7 @@ static int af9013_get_frontend(struct dvb_frontend *fe, break; } - return ret; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret);
[PATCH 13/15] af9015: move 2nd demod power-up wait different location
We need to wait 2nd demod power-up before download firmware. Move that wait to more correct location. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index ee0e354..53d478d 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -740,9 +740,6 @@ static int af9015_copy_firmware(struct dvb_usb_device *d) fw_params[2] = state->firmware_checksum >> 8; fw_params[3] = state->firmware_checksum & 0xff; - /* wait 2nd demodulator ready */ - msleep(100); - ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr, 0x98be, &val); if (ret) @@ -830,6 +827,9 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) /* copy firmware to 2nd demodulator */ if (state->dual_mode) { + /* Wait 2nd demodulator ready */ + msleep(100); + ret = af9015_copy_firmware(adap_to_d(adap)); if (ret) { dev_err(&adap_to_d(adap)->udev->dev, -- http://palosaari.fi/
[PATCH 15/15] af9013: refactor power control
Move power-up and power-down functionality to init/sleep ops and get rid of old function. Fixes and simplifies power-up functionality slightly. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 93 ++-- 1 file changed, 36 insertions(+), 57 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 40fd2ea..128d915 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -101,59 +101,6 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) return ret; } -static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) -{ - struct i2c_client *client = state->client; - int ret; - unsigned int utmp; - - dev_dbg(&client->dev, "onoff %d\n", onoff); - - /* enable reset */ - ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x10); - if (ret) - goto err; - - /* start reset mechanism */ - ret = regmap_write(state->regmap, 0xaeff, 0x01); - if (ret) - goto err; - - /* wait reset performs */ - ret = regmap_read_poll_timeout(state->regmap, 0xd417, utmp, - (utmp >> 1) & 0x01, 5000, 100); - if (ret) - goto err; - - if (!((utmp >> 1) & 0x01)) - return -ETIMEDOUT; - - if (onoff) { - /* clear reset */ - ret = regmap_update_bits(state->regmap, 0xd417, 0x02, 0x00); - if (ret) - goto err; - /* disable reset */ - ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x00); - if (ret) - goto err; - /* power on */ - ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x00); - if (ret) - goto err; - } else { - /* power off */ - ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x08); - if (ret) - goto err; - } - - return 0; -err: - dev_dbg(&client->dev, "failed %d\n", ret); - return ret; -} - static int af9013_statistics_ber_unc_start(struct dvb_frontend *fe) { struct af9013_state *state = fe->demodulator_priv; @@ -889,8 +836,18 @@ static int af9013_init(struct dvb_frontend *fe) dev_dbg(&client->dev, "\n"); - /* power on */ - ret = af9013_power_ctrl(state, 1); + /* ADC on */ + ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x00); + if (ret) + goto err; + + /* Clear reset */ + ret = regmap_update_bits(state->regmap, 0xd417, 0x02, 0x00); + if (ret) + goto err; + + /* Disable reset */ + ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x00); if (ret) goto err; @@ -1070,6 +1027,7 @@ static int af9013_sleep(struct dvb_frontend *fe) struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; int ret; + unsigned int utmp; dev_dbg(&client->dev, "\n"); @@ -1081,8 +1039,29 @@ static int af9013_sleep(struct dvb_frontend *fe) if (ret) goto err; - /* power off */ - ret = af9013_power_ctrl(state, 0); + /* Enable reset */ + ret = regmap_update_bits(state->regmap, 0xd417, 0x10, 0x10); + if (ret) + goto err; + + /* Start reset execution */ + ret = regmap_write(state->regmap, 0xaeff, 0x01); + if (ret) + goto err; + + /* Wait reset performs */ + ret = regmap_read_poll_timeout(state->regmap, 0xd417, utmp, + (utmp >> 1) & 0x01, 5000, 100); + if (ret) + goto err; + + if (!((utmp >> 1) & 0x01)) { + ret = -ETIMEDOUT; + goto err; + } + + /* ADC off */ + ret = regmap_update_bits(state->regmap, 0xd73a, 0x08, 0x08); if (ret) goto err; -- http://palosaari.fi/
[PATCH 02/15] af9013: move config values directly under driver state
It shorten, as typed chars, access to config values as there is one pointer less. Also, when config/platform data is passed to driver there could be some values that are not relevant to store state as such or not needed to store at all. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 62 ++-- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index b978002..7880a63 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -26,7 +26,14 @@ struct af9013_state { struct i2c_adapter *i2c; struct dvb_frontend fe; - struct af9013_config config; + u8 i2c_addr; + u32 clk; + u8 tuner; + u32 if_frequency; + u8 ts_mode; + bool spec_inv; + u8 api_version[4]; + u8 gpio[4]; /* tuner/demod RF and IF AGC limits used for signal strength calc */ u8 signal_strength_en, rf_50, rf_80, if_50, if_80; @@ -52,7 +59,7 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = priv->config.i2c_addr, + .addr = priv->i2c_addr, .flags = 0, .len = 3 + len, .buf = buf, @@ -90,12 +97,12 @@ static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, u8 buf[3]; struct i2c_msg msg[2] = { { - .addr = priv->config.i2c_addr, + .addr = priv->i2c_addr, .flags = 0, .len = 3, .buf = buf, }, { - .addr = priv->config.i2c_addr, + .addr = priv->i2c_addr, .flags = I2C_M_RD, .len = len, .buf = val, @@ -124,7 +131,7 @@ static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val, int ret, i; u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); - if ((priv->config.ts_mode == AF9013_TS_USB) && + if ((priv->ts_mode == AF9013_TS_USB) && ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { mbox |= ((len - 1) << 2); ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len); @@ -146,7 +153,7 @@ static int af9013_rd_regs(struct af9013_state *priv, u16 reg, u8 *val, int len) int ret, i; u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0); - if ((priv->config.ts_mode == AF9013_TS_USB) && + if ((priv->ts_mode == AF9013_TS_USB) && ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { mbox |= ((len - 1) << 2); ret = af9013_rd_regs_i2c(priv, mbox, reg, val, len); @@ -595,7 +602,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) /* program CFOE coefficients */ if (c->bandwidth_hz != state->bandwidth_hz) { for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { - if (coeff_lut[i].clock == state->config.clock && + if (coeff_lut[i].clock == state->clk && coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { break; } @@ -615,24 +622,24 @@ static int af9013_set_frontend(struct dvb_frontend *fe) if (fe->ops.tuner_ops.get_if_frequency) fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); else - if_frequency = state->config.if_frequency; + if_frequency = state->if_frequency; dev_dbg(&state->i2c->dev, "%s: if_frequency=%d\n", __func__, if_frequency); sampling_freq = if_frequency; - while (sampling_freq > (state->config.clock / 2)) - sampling_freq -= state->config.clock; + while (sampling_freq > (state->clk / 2)) + sampling_freq -= state->clk; if (sampling_freq < 0) { sampling_freq *= -1; - spec_inv = state->config.spec_inv; + spec_inv = state->spec_inv; } else { - spec_inv = !state->config.spec_inv; + spec_inv = !state->spec_inv; } - freq_cw = af9013_div(state, sampling_freq, state->config.clock,
[PATCH 14/15] af9013: refactor firmware download routine
Refactor firmware download routine. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 65 +--- 1 file changed, 30 insertions(+), 35 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 63c532a..40fd2ea 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -1136,64 +1136,59 @@ static const struct dvb_frontend_ops af9013_ops; static int af9013_download_firmware(struct af9013_state *state) { struct i2c_client *client = state->client; - int ret, i, len, remaining; + int ret, i, len, rem; unsigned int utmp; - const struct firmware *fw; + u8 buf[4]; u16 checksum = 0; - u8 fw_params[4]; - u8 *fw_file = AF9013_FIRMWARE; + const struct firmware *firmware; + const char *name = AF9013_FIRMWARE; - msleep(100); - /* check whether firmware is already running */ + dev_dbg(&client->dev, "\n"); + + /* Check whether firmware is already running */ ret = regmap_read(state->regmap, 0x98be, &utmp); if (ret) goto err; dev_dbg(&client->dev, "firmware status %02x\n", utmp); - if (utmp == 0x0c) /* fw is running, no need for download */ + if (utmp == 0x0c) return 0; dev_info(&client->dev, "found a '%s' in cold state, will try to load a firmware\n", af9013_ops.info.name); - /* request the firmware, this will block and timeout */ - ret = request_firmware(&fw, fw_file, &client->dev); + /* Request the firmware, will block and timeout */ + ret = request_firmware(&firmware, name, &client->dev); if (ret) { dev_info(&client->dev, "firmware file '%s' not found %d\n", -fw_file, ret); +name, ret); goto err; } dev_info(&client->dev, "downloading firmware from file '%s'\n", -fw_file); - - /* calc checksum */ - for (i = 0; i < fw->size; i++) - checksum += fw->data[i]; +name); - fw_params[0] = checksum >> 8; - fw_params[1] = checksum & 0xff; - fw_params[2] = fw->size >> 8; - fw_params[3] = fw->size & 0xff; - - /* write fw checksum & size */ - ret = regmap_bulk_write(state->regmap, 0x50fc, fw_params, - sizeof(fw_params)); + /* Write firmware checksum & size */ + for (i = 0; i < firmware->size; i++) + checksum += firmware->data[i]; + buf[0] = (checksum >> 8) & 0xff; + buf[1] = (checksum >> 0) & 0xff; + buf[2] = (firmware->size >> 8) & 0xff; + buf[3] = (firmware->size >> 0) & 0xff; + ret = regmap_bulk_write(state->regmap, 0x50fc, buf, 4); if (ret) goto err_release_firmware; - #define FW_ADDR 0x5100 /* firmware start address */ - #define LEN_MAX 16 /* max packet size */ - for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { - len = remaining; - if (len > LEN_MAX) - len = LEN_MAX; - + /* Download firmware */ + #define LEN_MAX 16 + for (rem = firmware->size; rem > 0; rem -= LEN_MAX) { + len = min(LEN_MAX, rem); ret = regmap_bulk_write(state->regmap, - FW_ADDR + fw->size - remaining, - &fw->data[fw->size - remaining], len); + 0x5100 + firmware->size - rem, + &firmware->data[firmware->size - rem], + len); if (ret) { dev_err(&client->dev, "firmware download failed %d\n", ret); @@ -1201,9 +1196,9 @@ static int af9013_download_firmware(struct af9013_state *state) } } - release_firmware(fw); + release_firmware(firmware); - /* request boot firmware */ + /* Boot firmware */ ret = regmap_write(state->regmap, 0xe205, 0x01); if (ret) goto err; @@ -1232,7 +1227,7 @@ static int af9013_download_firmware(struct af9013_state *state) return 0; err_release_firmware: - release_firmware(fw); + release_firmware(firmware); err: dev_dbg(&client->dev, "failed %d\n", ret); return ret; -- http://palosaari.fi/
[PATCH 01/15] af9015: use correct 7-bit i2c addresses
Driver was using wrong "8-bit" i2c addresses for demods and tuners. Internal demod i2c address was not set at all. These are needed to be fixed before proper i2c client binding is used. Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 24 +--- drivers/media/usb/dvb-usb-v2/af9015.h | 4 ++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index caa1e61..138416c 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -36,7 +36,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) state->buf[0] = req->cmd; state->buf[1] = state->seq++; - state->buf[2] = req->i2c_addr; + state->buf[2] = req->i2c_addr << 1; state->buf[3] = req->addr >> 8; state->buf[4] = req->addr & 0xff; state->buf[5] = req->mbox; @@ -471,6 +471,8 @@ static int af9015_read_config(struct dvb_usb_device *d) if (d->udev->speed == USB_SPEED_FULL) state->dual_mode = 0; + state->af9013_config[0].i2c_addr = AF9015_I2C_DEMOD; + if (state->dual_mode) { /* read 2nd demodulator I2C address */ req.addr = AF9015_EEPROM_DEMOD2_I2C; @@ -478,7 +480,7 @@ static int af9015_read_config(struct dvb_usb_device *d) if (ret) goto error; - state->af9013_config[1].i2c_addr = val; + state->af9013_config[1].i2c_addr = val >> 1; } for (i = 0; i < state->dual_mode + 1; i++) { @@ -870,12 +872,12 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) } static struct mt2060_config af9015_mt2060_config = { - .i2c_address = 0xc0, + .i2c_address = 0x60, .clock_out = 0, }; static struct qt1010_config af9015_qt1010_config = { - .i2c_address = 0xc4, + .i2c_address = 0x62, }; static struct tda18271_config af9015_tda18271_config = { @@ -884,7 +886,7 @@ static struct tda18271_config af9015_tda18271_config = { }; static struct mxl5005s_config af9015_mxl5003_config = { - .i2c_address = 0xc6, + .i2c_address = 0x63, .if_freq = IF_FREQ_457HZ, .xtal_freq = CRYSTAL_FREQ_1600HZ, .agc_mode= MXL_SINGLE_AGC, @@ -901,7 +903,7 @@ static struct mxl5005s_config af9015_mxl5003_config = { }; static struct mxl5005s_config af9015_mxl5005_config = { - .i2c_address = 0xc6, + .i2c_address = 0x63, .if_freq = IF_FREQ_457HZ, .xtal_freq = CRYSTAL_FREQ_1600HZ, .agc_mode= MXL_SINGLE_AGC, @@ -918,12 +920,12 @@ static struct mxl5005s_config af9015_mxl5005_config = { }; static struct mc44s803_config af9015_mc44s803_config = { - .i2c_address = 0xc0, + .i2c_address = 0x60, .dig_out = 1, }; static struct tda18218_config af9015_tda18218_config = { - .i2c_address = 0xc0, + .i2c_address = 0x60, .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */ }; @@ -954,7 +956,7 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, + ret = dvb_attach(tda18271_attach, adap->fe[0], 0x60, &adap_to_d(adap)->i2c_adap, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; @@ -975,7 +977,7 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, + ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, &adap_to_d(adap)->i2c_adap, DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; @@ -987,7 +989,7 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) case AF9013_TUNER_MXL5007T: ret = dvb_attach(mxl5007t_attach, adap->fe[0], &adap_to_d(adap)->i2c_adap, - 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; + 0x60, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_UNKNOWN: default: diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h index 2dd9231..3a9d981 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.h +++ b/drivers/media/usb/dv
[PATCH 12/15] af9013: remove unneeded register writes
Removed register writes are already chip defaults, are not required, are set later or belong to AF9015 USB interface. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 42 1 file changed, 42 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 6b86437..63c532a 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -894,11 +894,6 @@ static int af9013_init(struct dvb_frontend *fe) if (ret) goto err; - /* enable ADC */ - ret = regmap_write(state->regmap, 0xd73a, 0xa4); - if (ret) - goto err; - /* write API version to firmware */ ret = regmap_bulk_write(state->regmap, 0x9bf2, state->api_version, 4); if (ret) @@ -935,43 +930,6 @@ static int af9013_init(struct dvb_frontend *fe) if (ret) goto err; - /* set I2C master clock */ - ret = regmap_write(state->regmap, 0xd416, 0x14); - if (ret) - goto err; - - /* set 16 embx */ - ret = regmap_update_bits(state->regmap, 0xd700, 0x02, 0x02); - if (ret) - goto err; - - /* set no trigger */ - ret = regmap_update_bits(state->regmap, 0xd700, 0x04, 0x00); - if (ret) - goto err; - - /* set read-update bit for constellation */ - ret = regmap_update_bits(state->regmap, 0xd371, 0x02, 0x02); - if (ret) - goto err; - - /* settings for mp2if */ - if (state->ts_mode == AF9013_TS_MODE_USB) { - /* AF9015 split PSB to 1.5k + 0.5k */ - ret = regmap_update_bits(state->regmap, 0xd50b, 0x04, 0x04); - if (ret) - goto err; - } else { - /* AF9013 set mpeg to full speed */ - ret = regmap_update_bits(state->regmap, 0xd502, 0x10, 0x10); - if (ret) - goto err; - } - - ret = regmap_update_bits(state->regmap, 0xd520, 0x10, 0x10); - if (ret) - goto err; - /* load OFSM settings */ dev_dbg(&client->dev, "load ofsm settings\n"); len = ARRAY_SIZE(ofsm_init); -- http://palosaari.fi/
[PATCH 08/15] af9013: add dvbv5 cnr
Add support for DVBv5 CNR. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index a6b88ae..68091f2 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -228,6 +228,7 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) { struct af9013_state *state = fe->demodulator_priv; struct i2c_client *client = state->client; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, len; unsigned int utmp; u8 buf[3]; @@ -283,6 +284,9 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe) } state->snr = utmp * 10; /* dB/10 */ + c->cnr.stat[0].svalue = 1000 * utmp; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + return 0; err: dev_dbg(&client->dev, "failed %d\n", ret); @@ -1508,6 +1512,7 @@ static int af9013_probe(struct i2c_client *client, { struct af9013_state *state; struct af9013_platform_data *pdata = client->dev.platform_data; + struct dtv_frontend_properties *c; int ret, i; u8 firmware_version[4]; static const struct regmap_bus regmap_bus = { @@ -1572,6 +1577,10 @@ static int af9013_probe(struct i2c_client *client, /* Setup callbacks */ pdata->get_dvb_frontend = af9013_get_dvb_frontend; + /* Init stats to indicate which stats are supported */ + c = &state->fe.dtv_property_cache; + c->cnr.len = 1; + dev_info(&client->dev, "Afatech AF9013 successfully attached\n"); dev_info(&client->dev, "firmware version: %d.%d.%d.%d\n", firmware_version[0], firmware_version[1], -- http://palosaari.fi/
[PATCH 05/15] af9013: fix logging
We can simplify logging as we now have a proper i2c client to pass for kernel dev_* logging functions. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 202 +-- 1 file changed, 100 insertions(+), 102 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index dd7ac0a..781e958 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -51,14 +51,15 @@ struct af9013_state { }; /* write multiple registers */ -static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, +static int af9013_wr_regs_i2c(struct af9013_state *state, u8 mbox, u16 reg, const u8 *val, int len) { + struct i2c_client *client = state->client; int ret; u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = priv->client->addr, + .addr = state->client->addr, .flags = 0, .len = 3 + len, .buf = buf, @@ -66,9 +67,8 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, }; if (3 + len > sizeof(buf)) { - dev_warn(&priv->client->dev, -"%s: i2c wr reg=%04x: len=%d is too big!\n", -KBUILD_MODNAME, reg, len); + dev_warn(&client->dev, "i2c wr reg %04x, len %d, is too big!\n", +reg, len); return -EINVAL; } @@ -77,31 +77,32 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, buf[2] = mbox; memcpy(&buf[3], val, len); - ret = i2c_transfer(priv->client->adapter, msg, 1); + ret = i2c_transfer(state->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&priv->client->dev, "%s: i2c wr failed=%d reg=%04x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&client->dev, "i2c wr failed %d, reg %04x, len %d\n", +ret, reg, len); ret = -EREMOTEIO; } return ret; } /* read multiple registers */ -static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, +static int af9013_rd_regs_i2c(struct af9013_state *state, u8 mbox, u16 reg, u8 *val, int len) { + struct i2c_client *client = state->client; int ret; u8 buf[3]; struct i2c_msg msg[2] = { { - .addr = priv->client->addr, + .addr = state->client->addr, .flags = 0, .len = 3, .buf = buf, }, { - .addr = priv->client->addr, + .addr = state->client->addr, .flags = I2C_M_RD, .len = len, .buf = val, @@ -112,31 +113,31 @@ static int af9013_rd_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, buf[1] = (reg >> 0) & 0xff; buf[2] = mbox; - ret = i2c_transfer(priv->client->adapter, msg, 2); + ret = i2c_transfer(state->client->adapter, msg, 2); if (ret == 2) { ret = 0; } else { - dev_warn(&priv->client->dev, "%s: i2c rd failed=%d reg=%04x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&client->dev, "i2c rd failed %d, reg %04x, len %d\n", +ret, reg, len); ret = -EREMOTEIO; } return ret; } /* write multiple registers */ -static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val, +static int af9013_wr_regs(struct af9013_state *state, u16 reg, const u8 *val, int len) { int ret, i; u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); - if ((priv->ts_mode == AF9013_TS_USB) && + if ((state->ts_mode == AF9013_TS_USB) && ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { mbox |= ((len - 1) << 2); - ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len); + ret = af9013_wr_regs_i2c(state, mbox, reg, val, len); } else { for (i = 0; i < len; i++) { - ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1); + ret = af9013_wr_regs_i2c(state, mbox, reg+i, val+i, 1); if (ret) goto err;
[PATCH 04/15] af9033: use kernel 64-bit division
Replace own binary division with 64-bit multiply and division. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/af9013.c | 34 +++ drivers/media/dvb-frontends/af9013_priv.h | 1 + 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index f644182..dd7ac0a 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -277,33 +277,6 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) return ret; } -static u32 af9013_div(struct af9013_state *state, u32 a, u32 b, u32 x) -{ - u32 r = 0, c = 0, i; - - dev_dbg(&state->client->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); - - if (a > b) { - c = a / b; - a = a - c * b; - } - - for (i = 0; i < x; i++) { - if (a >= b) { - r += 1; - a -= b; - } - a <<= 1; - r <<= 1; - } - r = (c << (u32)x) + r; - - dev_dbg(&state->client->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n", - __func__, a, b, x, r, r); - - return r; -} - static int af9013_power_ctrl(struct af9013_state *state, u8 onoff) { int ret, i; @@ -638,8 +611,8 @@ static int af9013_set_frontend(struct dvb_frontend *fe) spec_inv = !state->spec_inv; } - freq_cw = af9013_div(state, sampling_freq, state->clk, - 23); + freq_cw = DIV_ROUND_CLOSEST_ULL((u64)sampling_freq * 0x80, + state->clk); if (spec_inv) freq_cw = 0x80 - freq_cw; @@ -1108,11 +1081,10 @@ static int af9013_init(struct dvb_frontend *fe) return -EINVAL; } - adc_cw = af9013_div(state, state->clk, 100ul, 19); + adc_cw = div_u64((u64)state->clk * 0x8, 100); buf[0] = (adc_cw >> 0) & 0xff; buf[1] = (adc_cw >> 8) & 0xff; buf[2] = (adc_cw >> 16) & 0xff; - ret = af9013_wr_regs(state, 0xd180, buf, 3); if (ret) goto err; diff --git a/drivers/media/dvb-frontends/af9013_priv.h b/drivers/media/dvb-frontends/af9013_priv.h index 31d6538..97b5b0c 100644 --- a/drivers/media/dvb-frontends/af9013_priv.h +++ b/drivers/media/dvb-frontends/af9013_priv.h @@ -24,6 +24,7 @@ #include "dvb_frontend.h" #include "af9013.h" #include +#include #define AF9013_FIRMWARE "dvb-fe-af9013.fw" -- http://palosaari.fi/
[PATCH 06/15] af9013: convert to regmap api
Use regmap for register access. Own low level i2c read and write routines for regmap is still needed because chip uses single command byte in addition to typical i2c register access. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/Kconfig | 1 + drivers/media/dvb-frontends/af9013.c | 598 +++--- drivers/media/dvb-frontends/af9013_priv.h | 1 + 3 files changed, 294 insertions(+), 306 deletions(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index e8c6554..3a260b8 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -436,6 +436,7 @@ config DVB_TDA10048 config DVB_AF9013 tristate "Afatech AF9013 demodulator" depends on DVB_CORE && I2C + select REGMAP default m if !MEDIA_SUBDRV_AUTOSELECT help Say Y when you want to support this frontend. diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 781e958..70102c1 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -20,11 +20,9 @@ #include "af9013_priv.h" -/* Max transfer size done by I2C transfer functions */ -#define MAX_XFER_SIZE 64 - struct af9013_state { struct i2c_client *client; + struct regmap *regmap; struct dvb_frontend fe; u32 clk; u8 tuner; @@ -50,181 +48,6 @@ struct af9013_state { struct delayed_work statistics_work; }; -/* write multiple registers */ -static int af9013_wr_regs_i2c(struct af9013_state *state, u8 mbox, u16 reg, - const u8 *val, int len) -{ - struct i2c_client *client = state->client; - int ret; - u8 buf[MAX_XFER_SIZE]; - struct i2c_msg msg[1] = { - { - .addr = state->client->addr, - .flags = 0, - .len = 3 + len, - .buf = buf, - } - }; - - if (3 + len > sizeof(buf)) { - dev_warn(&client->dev, "i2c wr reg %04x, len %d, is too big!\n", -reg, len); - return -EINVAL; - } - - buf[0] = (reg >> 8) & 0xff; - buf[1] = (reg >> 0) & 0xff; - buf[2] = mbox; - memcpy(&buf[3], val, len); - - ret = i2c_transfer(state->client->adapter, msg, 1); - if (ret == 1) { - ret = 0; - } else { - dev_warn(&client->dev, "i2c wr failed %d, reg %04x, len %d\n", -ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* read multiple registers */ -static int af9013_rd_regs_i2c(struct af9013_state *state, u8 mbox, u16 reg, - u8 *val, int len) -{ - struct i2c_client *client = state->client; - int ret; - u8 buf[3]; - struct i2c_msg msg[2] = { - { - .addr = state->client->addr, - .flags = 0, - .len = 3, - .buf = buf, - }, { - .addr = state->client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = val, - } - }; - - buf[0] = (reg >> 8) & 0xff; - buf[1] = (reg >> 0) & 0xff; - buf[2] = mbox; - - ret = i2c_transfer(state->client->adapter, msg, 2); - if (ret == 2) { - ret = 0; - } else { - dev_warn(&client->dev, "i2c rd failed %d, reg %04x, len %d\n", -ret, reg, len); - ret = -EREMOTEIO; - } - return ret; -} - -/* write multiple registers */ -static int af9013_wr_regs(struct af9013_state *state, u16 reg, const u8 *val, - int len) -{ - int ret, i; - u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); - - if ((state->ts_mode == AF9013_TS_USB) && - ((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { - mbox |= ((len - 1) << 2); - ret = af9013_wr_regs_i2c(state, mbox, reg, val, len); - } else { - for (i = 0; i < len; i++) { - ret = af9013_wr_regs_i2c(state, mbox, reg+i, val+i, 1); - if (ret) - goto err; - } - } - -err: - return 0; -} - -/* read multiple registers */ -static int af9013_rd_regs(struct af9013_state *state, u16 reg, u8 *val, int len) -{ - int ret, i; - u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(0 << 0); - - if ((state->ts_mode == AF9013_TS_USB) && - ((reg & 0xff00) != 0xff00)
[PATCH 09/15] af9015: fix and refactor i2c adapter algo logic
* fix write+read when write has more than one byte * remove lock, not needed on that case * remove useless i2c msg send loop, as we support only write, read and write+read as one go and nothing more Signed-off-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/af9015.c | 153 ++ 1 file changed, 79 insertions(+), 74 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 138416c..54c1d47 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -205,9 +205,9 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], { struct dvb_usb_device *d = i2c_get_adapdata(adap); struct af9015_state *state = d_to_priv(d); - int ret = 0, i = 0; + int ret; u16 addr; - u8 uninitialized_var(mbox), addr_len; + u8 mbox, addr_len; struct req_t req; /* @@ -232,84 +232,89 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate. | addr 0x3a | | addr 0xc6 | || || */ - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - while (i < num) { - if (msg[i].addr == state->af9013_config[0].i2c_addr || - msg[i].addr == state->af9013_config[1].i2c_addr) { - addr = msg[i].buf[0] << 8; - addr += msg[i].buf[1]; - mbox = msg[i].buf[2]; - addr_len = 3; - } else { - addr = msg[i].buf[0]; - addr_len = 1; - /* mbox is don't care in that case */ - } + if (msg[0].len == 0 || msg[0].flags & I2C_M_RD) { + addr = 0x; + mbox = 0; + addr_len = 0; + } else if (msg[0].len == 1) { + addr = msg[0].buf[0]; + mbox = 0; + addr_len = 1; + } else if (msg[0].len == 2) { + addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0; + mbox = 0; + addr_len = 2; + } else { + addr = msg[0].buf[0] << 8|msg[0].buf[1] << 0; + mbox = msg[0].buf[2]; + addr_len = 3; + } - if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { - if (msg[i].len > 3 || msg[i+1].len > 61) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) - req.cmd = READ_MEMORY; - else - req.cmd = READ_I2C; - req.i2c_addr = msg[i].addr; - req.addr = addr; - req.mbox = mbox; - req.addr_len = addr_len; - req.data_len = msg[i+1].len; - req.data = &msg[i+1].buf[0]; - ret = af9015_ctrl_msg(d, &req); - i += 2; - } else if (msg[i].flags & I2C_M_RD) { - if (msg[i].len > 61) { - ret = -EOPNOTSUPP; - goto error; - } - if (msg[i].addr == state->af9013_config[0].i2c_addr) { - ret = -EINVAL; - goto error; - } + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + /* i2c write */ + if (msg[0].len > 21) { + ret = -EOPNOTSUPP; + goto err; + } + if (msg[0].addr == state->af9013_config[0].i2c_addr) + req.cmd = WRITE_MEMORY; + else + req.cmd = WRITE_I2C; + req.i2c_addr = msg[0].addr; + req.addr = addr; + req.mbox = mbox; + req.addr_len = addr_len; + req.data_len = msg[0].len-addr_len; + req.data = &msg[0].buf[addr_len]; + ret = af9015_ctrl_msg(d, &req); + } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + /* i2c write + read */ + if (msg[0].len > 3 || msg[1].len > 61) { + ret = -EOPNOTSUPP; + goto err; + } + if (msg[0].addr == state->af9013_config[0].i2c_addr) + req.cmd = READ_MEMOR
Re: [PATCH] dvb-usb-af9035: load HID table
Hello Jaroslav Škarvada kirjoitti 2017-06-09 20:46: Automatically load sniffed HID table from Windows driver if USB_VID_ITETECH:USB_PID_ITETECH_IT9135_9006 device is present (e.g. Evolveo Mars) or if module parameter force_hid_tab_load is set. There is few issues I don't like this approach. Mostly that module parameter to select HID table. There is existing solution to select remote controller, it is ir-keytable and it should be used rather than defining device specific module parameter. If you look that HID table you could see there is 4 bytes NEC code and 3 bytes HID code. Remote controller seems to have 34 keys. Remote controller address bytes are 0x02bd, grepping existing remote controller keytables it could be Total Media In Hand remote controller (rc-total-media-in-hand.c). If not, then defining new keytable is needed. I did some research about issue and found 2 better solutions. 1) Configure HID table dynamically. Remote controller keytable has some needed information, but those KEY_* events needed to be translated to HID codes somehow. 2) Kill HID and then use CMD_IR_GET to get remote controller scancodes by polling. Solution 1 sounds most correct. No need to poll and decode by sw as hw does all the job. But it is most hardest to implement, I am not aware if anyone has done it yet. regards Antti -- http://palosaari.fi/
Re: [media-af9013] question about return value in function af9013_wr_regs()
Gustavo A. R. Silva kirjoitti 2017-06-09 00:51: Hello everybody, While looking into Coverity ID 1227035 I ran into the following piece of code at drivers/media/dvb-frontends/af9013.c:595: The issue here is that the value stored in variable _ret_ at line 608, is not being evaluated as it happens at line 662, 667, 672 and 677. Then after looking into function af9013_wr_regs(), I noticed that this function always returns zero, no matter what, as you can see below: 121static int af9013_wr_regs(struct af9013_state *priv, u16 reg, const u8 *val, 122int len) 123{ 124int ret, i; 125u8 mbox = (0 << 7)|(0 << 6)|(1 << 1)|(1 << 0); 126 127if ((priv->config.ts_mode == AF9013_TS_USB) && 128((reg & 0xff00) != 0xff00) && ((reg & 0xff00) != 0xae00)) { 129mbox |= ((len - 1) << 2); 130ret = af9013_wr_regs_i2c(priv, mbox, reg, val, len); 131} else { 132for (i = 0; i < len; i++) { 133ret = af9013_wr_regs_i2c(priv, mbox, reg+i, val+i, 1); 134if (ret) 135goto err; 136} 137} 138 139err: 140return 0; 141} That function should return error code on error case, not zero always. regards Antti -- http://palosaari.fi/
Re: [PATCH 1/3] [media] si2157: get chip id during probing
On 05/15/2017 11:28 PM, Andreas Kemnade wrote: Hi, On Sun, 23 Apr 2017 15:19:21 +0300 Antti Palosaari wrote: On 03/16/2017 12:22 AM, Andreas Kemnade wrote: If the si2157 is behind a e.g. si2168, the si2157 will at least in some situations not be readable after the si268 got the command 0101. It still accepts commands but the answer is just ff. So read the chip id before that so the information is not lost. The following line in kernel output is a symptome of that problem: si2157 7-0063: unknown chip version Si21255-\x\x\x That is hackish solution :( Somehow I2C reads should be get working rather than making this kind of work-around. Returning 0xff to i2c reads means that signal strength also shows some wrong static value? Also this is needed for the Terratec CinergyTC2. I see the ff even on windows. So it cannot be solved by usb-sniffing of a working system, so, again how should we proceed? a) not support dvb sticks which do not work with your preferred order of initialization. b) change order of initialisation (maybe optionally add a flag like INIT_TUNER_BEFORE_DEMOD to avoid risk of breaking other things) c) something like the current patch. d) while(!i2c_readable(tuner)) { write_random_data_to_demod(); write_random_data_it9306_bridge(); } remember_random_data(); There was not much feedback here. If it is not possible to fix i2c communication then better to add some device specific logic to i2c adapter in order to meet demod/tuner requirements. An excerpt from my windows sniff logs: ep: 02 l: 15 GEN_I2C_WR 00 0603c61201 ep: 02 l:0 ep: 81 l:0 ep: 81 l:5 042300dcff ep: 02 l:9 GEN_I2C_RD 00 0603c6 ep: 02 l:0 ep: 81 l:0 ep: 81 l: 11 0a240080ff5b02 ep: 02 l: 15 GEN_I2C_WR 00 0603c6140011070300 ep: 02 l:0 ep: 81 l:0 ep: 81 l:5 042500daff ep: 02 l:9 GEN_I2C_RD 00 0403c6 ep: 02 l:0 ep: 81 l:0 ep: 81 l:9 08260080ff5901 here you see all the from the device. Regards, Andreas regards Antti -- http://palosaari.fi/
Re: [PATCH 1/3] [media] si2157: get chip id during probing
On 03/16/2017 12:22 AM, Andreas Kemnade wrote: If the si2157 is behind a e.g. si2168, the si2157 will at least in some situations not be readable after the si268 got the command 0101. It still accepts commands but the answer is just ff. So read the chip id before that so the information is not lost. The following line in kernel output is a symptome of that problem: si2157 7-0063: unknown chip version Si21255-\x\x\x That is hackish solution :( Somehow I2C reads should be get working rather than making this kind of work-around. Returning 0xff to i2c reads means that signal strength also shows some wrong static value? regards Antti -- http://palosaari.fi/
[GIT PULL 4.12] si2157: Si2141 tuner support
That patch set replaces existing si2146 support with new one, that looks more correct for my eyes. Antti The following changes since commit 7ca0ef3da09888b303991edb80cd0283ee641c9e: Merge tag 'v4.11-rc5' into patchwork (2017-04-04 11:11:43 -0300) are available in the git repository at: git://linuxtv.org/anttip/media_tree.git si2168 for you to fetch changes up to c9110a61811b9349ac64c3e50fd927c580e2eacd: si2157: Add support for Si2141-A10 (2017-04-06 16:48:52 +0300) -------- Antti Palosaari (1): si2157: revert si2157: Si2141/2151 tuner support Stefan Brüns (1): si2157: Add support for Si2141-A10 drivers/media/tuners/si2157.c | 85 +++-- 1 file changed, 23 insertions(+), 62 deletions(-) -- http://palosaari.fi/
[PATCH 1/2] si2157: revert si2157: Si2141/2151 tuner support
'Reset' loop does not look correct. I tested it very many times and it never repeated those commands. If problem, it tries to solve, really occurs on some situations better solution should be find out. There is another patch which does not have such hackish looking loop. Lets change to it. Cc: Evgeny Plehov Signed-off-by: Antti Palosaari --- drivers/media/tuners/si2157.c | 70 -- drivers/media/tuners/si2157_priv.h | 2 -- 2 files changed, 6 insertions(+), 66 deletions(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index b46b149..57b2508 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -1,5 +1,5 @@ /* - * Silicon Labs Si2141/2146/2147/2148/2151/2157/2158 silicon tuner driver + * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver * * Copyright (C) 2014 Antti Palosaari * @@ -75,7 +75,6 @@ static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd) return ret; } -#define MAX_RESET_ATTEMPTS 10 static int si2157_init(struct dvb_frontend *fe) { struct i2c_client *client = fe->tuner_priv; @@ -85,7 +84,7 @@ static int si2157_init(struct dvb_frontend *fe) struct si2157_cmd cmd; const struct firmware *fw; const char *fw_name; - unsigned int uitmp, chip_id, i; + unsigned int uitmp, chip_id; dev_dbg(&client->dev, "\n"); @@ -103,44 +102,14 @@ static int si2157_init(struct dvb_frontend *fe) if (uitmp == dev->if_frequency / 1000) goto warm; - if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { - for (i = 0; i < MAX_RESET_ATTEMPTS; i++) { - /* reset */ - memcpy(cmd.args, "\xc0\x05\x00\x00", 4); - cmd.wlen = 4; - cmd.rlen = 1; - ret = si2157_cmd_execute(client, &cmd); - if (ret) - goto err; - - memcpy(cmd.args, "\xc0\x00\x0d\x0e\x00\x01\x01\x01\x01\x03", 10); - cmd.wlen = 10; - cmd.rlen = 1; - ret = si2157_cmd_execute(client, &cmd); - if (ret) - goto err; - if (cmd.args[0] != 0xfe) - break; - } - if (i >= MAX_RESET_ATTEMPTS) - goto err; - } - /* power up */ - switch (dev->chiptype) { - case SI2157_CHIPTYPE_SI2146: + if (dev->chiptype == SI2157_CHIPTYPE_SI2146) { memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9); cmd.wlen = 9; - break; - case SI2157_CHIPTYPE_SI2141: - memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x08\x01", 7); - cmd.wlen = 7; - break; - default: + } else { memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15); cmd.wlen = 15; } - cmd.rlen = 1; ret = si2157_cmd_execute(client, &cmd); if (ret) @@ -162,8 +131,6 @@ static int si2157_init(struct dvb_frontend *fe) #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0) #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0) - #define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0) - #define SI2151_A10 ('A' << 24 | 51 << 16 | '1' << 8 | '0' << 0) switch (chip_id) { case SI2158_A20: @@ -175,10 +142,6 @@ static int si2157_init(struct dvb_frontend *fe) case SI2146_A10: fw_name = NULL; break; - case SI2141_A10: - case SI2151_A10: - fw_name = SI2141_A10_FIRMWARE; - break; default: dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n", cmd.args[2], cmd.args[1], @@ -251,23 +214,6 @@ static int si2157_init(struct dvb_frontend *fe) dev_info(&client->dev, "firmware version: %c.%c.%d\n", cmd.args[6], cmd.args[7], cmd.args[8]); - - if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { - /* set clock */ - memcpy(cmd.args, "\xc0\x00\x0d", 3); - cmd.wlen = 3; - cmd.rlen = 1; - ret = si215
[PATCH 2/2] si2157: Add support for Si2141-A10
From: Stefan Brüns The Si2141 needs two distinct commands for powerup/reset, otherwise it will not respond to chip revision requests. It also needs a firmware to run properly. Cc: Evgeny Plehov Signed-off-by: Stefan Brüns Signed-off-by: Antti Palosaari --- drivers/media/tuners/si2157.c | 23 +-- drivers/media/tuners/si2157_priv.h | 2 ++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 57b2508..e35b1fa 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -106,6 +106,9 @@ static int si2157_init(struct dvb_frontend *fe) if (dev->chiptype == SI2157_CHIPTYPE_SI2146) { memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9); cmd.wlen = 9; + } else if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { + memcpy(cmd.args, "\xc0\x00\x0d\x0e\x00\x01\x01\x01\x01\x03", 10); + cmd.wlen = 10; } else { memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15); cmd.wlen = 15; @@ -115,6 +118,15 @@ static int si2157_init(struct dvb_frontend *fe) if (ret) goto err; + /* Si2141 needs a second command before it answers the revision query */ + if (dev->chiptype == SI2157_CHIPTYPE_SI2141) { + memcpy(cmd.args, "\xc0\x08\x01\x02\x00\x00\x01", 7); + cmd.wlen = 7; + ret = si2157_cmd_execute(client, &cmd); + if (ret) + goto err; + } + /* query chip revision */ memcpy(cmd.args, "\x02", 1); cmd.wlen = 1; @@ -131,12 +143,16 @@ static int si2157_init(struct dvb_frontend *fe) #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) #define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0) #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0) + #define SI2141_A10 ('A' << 24 | 41 << 16 | '1' << 8 | '0' << 0) switch (chip_id) { case SI2158_A20: case SI2148_A20: fw_name = SI2158_A20_FIRMWARE; break; + case SI2141_A10: + fw_name = SI2141_A10_FIRMWARE; + break; case SI2157_A30: case SI2147_A30: case SI2146_A10: @@ -371,7 +387,7 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) static const struct dvb_tuner_ops si2157_ops = { .info = { - .name = "Silicon Labs Si2146/2147/2148/2157/2158", + .name = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158", .frequency_min = 4200, .frequency_max = 87000, }, @@ -471,6 +487,7 @@ static int si2157_probe(struct i2c_client *client, #endif dev_info(&client->dev, "Silicon Labs %s successfully attached\n", + dev->chiptype == SI2157_CHIPTYPE_SI2141 ? "Si2141" : dev->chiptype == SI2157_CHIPTYPE_SI2146 ? "Si2146" : "Si2147/2148/2157/2158"); @@ -508,6 +525,7 @@ static int si2157_remove(struct i2c_client *client) static const struct i2c_device_id si2157_id_table[] = { {"si2157", SI2157_CHIPTYPE_SI2157}, {"si2146", SI2157_CHIPTYPE_SI2146}, + {"si2141", SI2157_CHIPTYPE_SI2141}, {} }; MODULE_DEVICE_TABLE(i2c, si2157_id_table); @@ -524,7 +542,8 @@ static struct i2c_driver si2157_driver = { module_i2c_driver(si2157_driver); -MODULE_DESCRIPTION("Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver"); +MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver"); MODULE_AUTHOR("Antti Palosaari "); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(SI2158_A20_FIRMWARE); +MODULE_FIRMWARE(SI2141_A10_FIRMWARE); diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index d6b2c7b..e6436f7 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -42,6 +42,7 @@ struct si2157_dev { #define SI2157_CHIPTYPE_SI2157 0 #define SI2157_CHIPTYPE_SI2146 1 +#define SI2157_CHIPTYPE_SI2141 2 /* firmware command struct */ #define SI2157_ARGLEN 30 @@ -52,5 +53,6 @@ struct si2157_cmd { }; #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" +#define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw" #endif -- http://palosaari.fi/
[GIT PULL 4.12] mn88472 statistics
The following changes since commit 700ea5e0e0dd70420a04e703ff264cc133834cba: Merge tag 'v4.11-rc1' into patchwork (2017-03-06 06:49:34 -0300) are available in the git repository at: git://linuxtv.org/anttip/media_tree.git mn88472 for you to fetch changes up to ea003f23ec598c46a31ad9bfe0e4d258f04edc0b: mn88472: implement PER statistics (2017-03-17 18:45:48 +0200) -------- Antti Palosaari (3): mn88472: implement signal strength statistics mn88472: implement cnr statistics mn88472: implement PER statistics drivers/media/dvb-frontends/mn88472.c | 134 -- drivers/media/dvb-frontends/mn88472_priv.h | 1 + 2 files changed, 133 insertions(+), 2 deletions(-) -- http://palosaari.fi/
[PATCH 3/3] mn88472: implement PER statistics
Implement DVBv5 PER. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/mn88472.c | 22 ++ 1 file changed, 22 insertions(+) diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c index c7e5f63..f6938f96 100644 --- a/drivers/media/dvb-frontends/mn88472.c +++ b/drivers/media/dvb-frontends/mn88472.c @@ -179,6 +179,26 @@ static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } + /* PER */ + if (*status & FE_HAS_SYNC) { + ret = regmap_bulk_read(dev->regmap[0], 0xe1, buf, 4); + if (ret) + goto err; + + utmp1 = buf[0] << 8 | buf[1] << 0; + utmp2 = buf[2] << 8 | buf[3] << 0; + dev_dbg(&client->dev, "block_error=%u block_count=%u\n", + utmp1, utmp2); + + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += utmp1; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += utmp2; + } else { + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + return 0; err: dev_dbg(&client->dev, "failed=%d\n", ret); @@ -654,6 +674,8 @@ static int mn88472_probe(struct i2c_client *client, c = &dev->fe.dtv_property_cache; c->strength.len = 1; c->cnr.len = 1; + c->block_error.len = 1; + c->block_count.len = 1; /* Setup callbacks */ pdata->get_dvb_frontend = mn88472_get_dvb_frontend; -- http://palosaari.fi/
[PATCH 1/3] mn88472: implement signal strength statistics
Implement DVBv5 signal strength on relative scale. Signed-off-by: Antti Palosaari --- drivers/media/dvb-frontends/mn88472.c | 28 ++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c index 29dd13b..25dd742 100644 --- a/drivers/media/dvb-frontends/mn88472.c +++ b/drivers/media/dvb-frontends/mn88472.c @@ -28,8 +28,9 @@ static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) struct i2c_client *client = fe->demodulator_priv; struct mn88472_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - unsigned int utmp; + int ret, i; + unsigned int utmp, utmp1; + u8 buf[2]; if (!dev->active) { ret = -EAGAIN; @@ -77,6 +78,24 @@ static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status) goto err; } + /* Signal strength */ + if (*status & FE_HAS_SIGNAL) { + for (i = 0; i < 2; i++) { + ret = regmap_bulk_read(dev->regmap[2], 0x8e + i, + &buf[i], 1); + if (ret) + goto err; + } + + utmp1 = buf[0] << 8 | buf[1] << 0 | buf[0] >> 2; + dev_dbg(&client->dev, "strength=%u\n", utmp1); + + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = utmp1; + } else { + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + return 0; err: dev_dbg(&client->dev, "failed=%d\n", ret); @@ -462,6 +481,7 @@ static int mn88472_probe(struct i2c_client *client, { struct mn88472_config *pdata = client->dev.platform_data; struct mn88472_dev *dev; + struct dtv_frontend_properties *c; int ret; unsigned int utmp; static const struct regmap_config regmap_config = { @@ -547,6 +567,10 @@ static int mn88472_probe(struct i2c_client *client, *pdata->fe = &dev->fe; i2c_set_clientdata(client, dev); + /* Init stats to indicate which stats are supported */ + c = &dev->fe.dtv_property_cache; + c->strength.len = 1; + /* Setup callbacks */ pdata->get_dvb_frontend = mn88472_get_dvb_frontend; -- http://palosaari.fi/