From mboxrd@z Thu Jan 1 00:00:00 1970 From: Jean-Francois Moine Subject: [PATCH v2] ASoC: tda998x: add a codec to the HDMI transmitter Date: Fri, 4 Jul 2014 09:17:33 +0200 Message-ID: <20140704091733.10258cfe@armhf> Mime-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Return-path: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To: Mark Brown , Russell King - ARM Linux Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org, lgirdwood@gmail.com, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org List-Id: alsa-devel@alsa-project.org VGhpcyBwYXRjaCBhZGRzIGEgQ09ERUMgZnVuY3Rpb24gdG8gdGhlIE5YUCBUREE5OTh4IEhETUkg dHJhbnNtaXR0ZXIuCgpUaGUgQ09ERUMgaGFuZGxlcyBib3RoIEkyUyBhbmQgUy9QRElGIGlucHV0 IGFuZCBkb2VzIGR5bmFtaWMgaW5wdXQKc3dpdGNoIGluIHRoZSBUREE5OTh4IEkyQyBkcml2ZXIg b24gc3RhcnQvc3RvcCBhdWRpbyBzdHJlYW1pbmcuCgpTaWduZWQtb2ZmLWJ5OiBKZWFuLUZyYW5j b2lzIE1vaW5lIDxtb2luZWpmQGZyZWUuZnI+Ci0tLQp2MjogY2hlY2sgZG91YmxlIHN0cmVhbSBz dGFydCAoTWFyayBCcm93bikKLS0tCiAuLi4vZGV2aWNldHJlZS9iaW5kaW5ncy9kcm0vaTJjL3Rk YTk5OHgudHh0ICAgICAgICB8ICAxMyArKwogZHJpdmVycy9ncHUvZHJtL2kyYy9NYWtlZmlsZSAg ICAgICAgICAgICAgICAgICAgICAgfCAgIDIgKy0KIGRyaXZlcnMvZ3B1L2RybS9pMmMvdGRhOTk4 eF9jb2RlYy5jICAgICAgICAgICAgICAgIHwgMjQ3ICsrKysrKysrKysrKysrKysrKysrKwogZHJp dmVycy9ncHUvZHJtL2kyYy90ZGE5OTh4X2Rydi5jICAgICAgICAgICAgICAgICAgfCAgNzQgKysr Ky0tCiBkcml2ZXJzL2dwdS9kcm0vaTJjL3RkYTk5OHhfZHJ2LmggICAgICAgICAgICAgICAgICB8 ICAzMiArKysKIGluY2x1ZGUvZHJtL2kyYy90ZGE5OTh4LmggICAgICAgICAgICAgICAgICAgICAg ICAgIHwgICAxICsKIDYgZmlsZXMgY2hhbmdlZCwgMzQ4IGluc2VydGlvbnMoKyksIDIxIGRlbGV0 aW9ucygtKQogY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvZ3B1L2RybS9pMmMvdGRhOTk4eF9j b2RlYy5jCiBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9ncHUvZHJtL2kyYy90ZGE5OTh4X2Ry di5oCgpkaWZmIC0tZ2l0IGEvRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL2RybS9p MmMvdGRhOTk4eC50eHQgYi9Eb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvZHJtL2ky Yy90ZGE5OTh4LnR4dAppbmRleCBkN2RmMDFjLi43Y2U0ZWFjIDEwMDY0NAotLS0gYS9Eb2N1bWVu dGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvZHJtL2kyYy90ZGE5OTh4LnR4dAorKysgYi9Eb2N1 bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvZHJtL2kyYy90ZGE5OTh4LnR4dApAQCAtMTUs NiArMTUsMTUgQEAgT3B0aW9uYWwgcHJvcGVydGllczoKICAgLSB2aWRlby1wb3J0czogMjQgYml0 cyB2YWx1ZSB3aGljaCBkZWZpbmVzIGhvdyB0aGUgdmlkZW8gY29udHJvbGxlcgogCW91dHB1dCBp cyB3aXJlZCB0byB0aGUgVERBOTk4eCBpbnB1dCAtIGRlZmF1bHQ6IDwweDIzMDE0NT4KIAorICAt IGF1ZGlvLXBvcnRzOiBvbmUgb3IgdHdvIHZhbHVlcyBjb3JyZXNwb25kaW5nIHRvIGVudHJpZXMg aW4KKwl0aGUgYXVkaW8tcG9ydC1uYW1lcyBwcm9wZXJ0eS4KKworICAtIGF1ZGlvLXBvcnQtbmFt ZXM6IG11c3QgY29udGFpbiAiaTJzIiwgInNwZGlmIiBlbnRyaWVzCisJbWF0Y2hpbmcgZW50cmll cyBpbiB0aGUgYXVkaW8tcG9ydHMgcHJvcGVydHkuCisKKyAgLSAjc291bmQtZGFpLWNlbGxzOiBt dXN0IGJlIHNldCB0byA8MT4gZm9yIHVzZSB3aXRoIHRoZSBzaW1wbGUtY2FyZC4KKwlUaGUgREFJ IDAgaXMgdGhlIEkyUyBpbnB1dCBhbmQgdGhlIERBSSAxIGlzIHRoZSBTL1BESUYgaW5wdXQuCisK IEV4YW1wbGU6CiAKIAl0ZGE5OTh4OiBoZG1pLWVuY29kZXIgewpAQCAtMjQsNCArMzMsOCBAQCBF eGFtcGxlOgogCQlpbnRlcnJ1cHRzID0gPDI3IDI+OwkJLyogZmFsbGluZyBlZGdlICovCiAJCXBp bmN0cmwtMCA9IDwmcG14X2NhbWVyYT47CiAJCXBpbmN0cmwtbmFtZXMgPSAiZGVmYXVsdCI7CisK KwkJYXVkaW8tcG9ydHMgPSA8MHgwMz4sIDwweDA0PjsKKwkJYXVkaW8tcG9ydC1uYW1lcyA9ICJp MnMiLCAic3BkaWYiOworCQkjc291bmQtZGFpLWNlbGxzID0gPDE+OwogCX07CmRpZmYgLS1naXQg YS9kcml2ZXJzL2dwdS9kcm0vaTJjL01ha2VmaWxlIGIvZHJpdmVycy9ncHUvZHJtL2kyYy9NYWtl ZmlsZQppbmRleCA0M2FhMzNiLi5mMmQ2MjVjIDEwMDY0NAotLS0gYS9kcml2ZXJzL2dwdS9kcm0v aTJjL01ha2VmaWxlCisrKyBiL2RyaXZlcnMvZ3B1L2RybS9pMmMvTWFrZWZpbGUKQEAgLTYsNSAr Niw1IEBAIG9iai0kKENPTkZJR19EUk1fSTJDX0NINzAwNikgKz0gY2g3MDA2Lm8KIHNpbDE2NC15 IDo9IHNpbDE2NF9kcnYubwogb2JqLSQoQ09ORklHX0RSTV9JMkNfU0lMMTY0KSArPSBzaWwxNjQu bwogCi10ZGE5OTh4LXkgOj0gdGRhOTk4eF9kcnYubwordGRhOTk4eC15IDo9IHRkYTk5OHhfZHJ2 Lm8gdGRhOTk4eF9jb2RlYy5vCiBvYmotJChDT05GSUdfRFJNX0kyQ19OWFBfVERBOTk4WCkgKz0g dGRhOTk4eC5vCmRpZmYgLS1naXQgYS9kcml2ZXJzL2dwdS9kcm0vaTJjL3RkYTk5OHhfY29kZWMu YyBiL2RyaXZlcnMvZ3B1L2RybS9pMmMvdGRhOTk4eF9jb2RlYy5jCm5ldyBmaWxlIG1vZGUgMTAw NjQ0CmluZGV4IDAwMDAwMDAuLmUyMmY5NzQKLS0tIC9kZXYvbnVsbAorKysgYi9kcml2ZXJzL2dw dS9kcm0vaTJjL3RkYTk5OHhfY29kZWMuYwpAQCAtMCwwICsxLDI0NyBAQAorLyoKKyAqIEFMU0Eg U29DIFREQTk5OFggQ09ERUMKKyAqCisgKiBDb3B5cmlnaHQgKEMpIDIwMTQgSmVhbi1GcmFuY29p cyBNb2luZQorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJl ZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5CisgKiBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhl IEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIHZlcnNpb24gMiBhcworICogcHVibGlzaGVkIGJ5 IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24uCisgKi8KKworI2luY2x1ZGUgPGxpbnV4L21v ZHVsZS5oPgorI2luY2x1ZGUgPHNvdW5kL3NvYy5oPgorI2luY2x1ZGUgPHNvdW5kL3BjbS5oPgor I2luY2x1ZGUgPHNvdW5kL3BjbV9wYXJhbXMuaD4KKyNpbmNsdWRlIDxsaW51eC9vZi5oPgorI2lu Y2x1ZGUgPGxpbnV4L2kyYy5oPgorI2luY2x1ZGUgPGRybS9kcm1fZW5jb2Rlcl9zbGF2ZS5oPgor I2luY2x1ZGUgPGRybS9pMmMvdGRhOTk4eC5oPgorCisjaW5jbHVkZSAidGRhOTk4eF9kcnYuaCIK KworI2RlZmluZSBUREE5OThYX0ZPUk1BVFMJKFNORFJWX1BDTV9GTVRCSVRfUzE2X0xFIHwgXAor CQkJU05EUlZfUENNX0ZNVEJJVF9TMjBfM0xFIHwgXAorCQkJU05EUlZfUENNX0ZNVEJJVF9TMjRf TEUgfCBcCisJCQlTTkRSVl9QQ01fRk1UQklUX1MzMl9MRSkKKworc3RhdGljIGludCB0ZGFfc3Rh cnR1cChzdHJ1Y3Qgc25kX3BjbV9zdWJzdHJlYW0gKnN1YnN0cmVhbSwKKwkJCXN0cnVjdCBzbmRf c29jX2RhaSAqZGFpKQoreworCXN0cnVjdCB0ZGE5OTh4X3ByaXYgKnByaXYgPSBzbmRfc29jX2Nv ZGVjX2dldF9kcnZkYXRhKGRhaS0+Y29kZWMpOworCXU4ICplbGQgPSBwcml2LT5lbGQ7CisJc3Ry dWN0IHNuZF9wY21fcnVudGltZSAqcnVudGltZSA9IHN1YnN0cmVhbS0+cnVudGltZTsKKwl1OCAq c2FkOworCWludCBzYWRfY291bnQ7CisJdW5zaWduZWQgZWxkX3ZlciwgbW5sLCByYXRlX21hc2s7 CisJdW5zaWduZWQgbWF4X2NoYW5uZWxzLCBmbXQ7CisJdTY0IGZvcm1hdHM7CisJc3RydWN0IHNu ZF9wY21faHdfY29uc3RyYWludF9saXN0ICpyYXRlX2NvbnN0cmFpbnRzID0KKwkJCSZwcml2LT5y YXRlX2NvbnN0cmFpbnRzOworCXN0YXRpYyBjb25zdCB1MzIgaGRtaV9yYXRlc1tdID0geworCQkz MjAwMCwgNDQxMDAsIDQ4MDAwLCA4ODIwMCwgOTYwMCwgMTc2NDAwLCAxOTIwMDAKKwl9OworCisJ LyogY2hlY2sgaWYgc3RyZWFtaW5nIGlzIGFscmVhZHkgYWN0aXZlICovCisJaWYgKHByaXYtPmRh aV9pZCAhPSBBRk1UX05PX0FVRElPKQorCQlyZXR1cm4gLUVCVVNZOworCXByaXYtPmRhaV9pZCA9 IGRhaS0+aWQ7CisKKwlpZiAoIWVsZCkKKwkJcmV0dXJuIDA7CisKKwkvKiBhZGp1c3QgdGhlIGh3 IHBhcmFtcyBmcm9tIHRoZSBFTEQgKEVESUQpICovCisJZWxkX3ZlciA9IGVsZFswXSA+PiAzOwor CWlmIChlbGRfdmVyICE9IDIgJiYgZWxkX3ZlciAhPSAzMSkKKwkJcmV0dXJuIDA7CisKKwltbmwg PSBlbGRbNF0gJiAweDFmOworCWlmIChtbmwgPiAxNikKKwkJcmV0dXJuIDA7CisKKwlzYWRfY291 bnQgPSBlbGRbNV0gPj4gNDsKKwlzYWQgPSBlbGQgKyAyMCArIG1ubDsKKworCS8qIFN0YXJ0IGZy b20gdGhlIGJhc2ljIGF1ZGlvIHNldHRpbmdzICovCisJbWF4X2NoYW5uZWxzID0gMjsKKwlyYXRl X21hc2sgPSAwOworCWZtdCA9IDA7CisJd2hpbGUgKHNhZF9jb3VudC0tKSB7CisJCXN3aXRjaCAo c2FkWzBdICYgMHg3OCkgeworCQljYXNlIDB4MDg6IC8qIFBDTSAqLworCQkJbWF4X2NoYW5uZWxz ID0gbWF4KG1heF9jaGFubmVscywgKHNhZFswXSAmIDcpICsgMXUpOworCQkJcmF0ZV9tYXNrIHw9 IHNhZFsxXTsKKwkJCWZtdCB8PSBzYWRbMl0gJiAweDA3OworCQkJYnJlYWs7CisJCX0KKwkJc2Fk ICs9IDM7CisJfQorCisJLyogc2V0IHRoZSBjb25zdHJhaW50cyAqLworCXJhdGVfY29uc3RyYWlu dHMtPmxpc3QgPSBoZG1pX3JhdGVzOworCXJhdGVfY29uc3RyYWludHMtPmNvdW50ID0gQVJSQVlf U0laRShoZG1pX3JhdGVzKTsKKwlyYXRlX2NvbnN0cmFpbnRzLT5tYXNrID0gcmF0ZV9tYXNrOwor CXNuZF9wY21faHdfY29uc3RyYWludF9saXN0KHJ1bnRpbWUsIDAsCisJCQkJCVNORFJWX1BDTV9I V19QQVJBTV9SQVRFLAorCQkJCQlyYXRlX2NvbnN0cmFpbnRzKTsKKworCWZvcm1hdHMgPSAwOwor CWlmIChmbXQgJiAxKQorCQlmb3JtYXRzIHw9IFNORFJWX1BDTV9GTVRCSVRfUzE2X0xFOworCWlm IChmbXQgJiAyKQorCQlmb3JtYXRzIHw9IFNORFJWX1BDTV9GTVRCSVRfUzIwXzNMRTsKKwlpZiAo Zm10ICYgNCkKKwkJZm9ybWF0cyB8PSBTTkRSVl9QQ01fRk1UQklUX1MyNF9MRTsKKwlzbmRfcGNt X2h3X2NvbnN0cmFpbnRfbWFzazY0KHJ1bnRpbWUsCisJCQkJU05EUlZfUENNX0hXX1BBUkFNX0ZP Uk1BVCwKKwkJCQlmb3JtYXRzKTsKKworCXNuZF9wY21faHdfY29uc3RyYWludF9taW5tYXgocnVu dGltZSwKKwkJCQlTTkRSVl9QQ01fSFdfUEFSQU1fQ0hBTk5FTFMsCisJCQkJMSwgbWF4X2NoYW5u ZWxzKTsKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGludCB0ZGFfaHdfcGFyYW1zKHN0cnVjdCBz bmRfcGNtX3N1YnN0cmVhbSAqc3Vic3RyZWFtLAorCQkJc3RydWN0IHNuZF9wY21faHdfcGFyYW1z ICpwYXJhbXMsCisJCQlzdHJ1Y3Qgc25kX3NvY19kYWkgKmRhaSkKK3sKKwlzdHJ1Y3QgdGRhOTk4 eF9wcml2ICpwcml2ID0gc25kX3NvY19jb2RlY19nZXRfZHJ2ZGF0YShkYWktPmNvZGVjKTsKKwor CS8qIFJlcXVpcmVzIGFuIGF0dGFjaGVkIGRpc3BsYXkgKi8KKwlpZiAoIXByaXYtPmVuY29kZXIt PmNydGMpCisJCXJldHVybiAtRU5PREVWOworCisJLyogaWYgc2FtZSBpbnB1dCBhbmQgc2FtZSBw YXJhbWV0ZXJzLCBkbyBub3QgZG8gYSBmdWxsIHN3aXRjaCAqLworCWlmIChkYWktPmlkID09IHBy aXYtPnBhcmFtcy5hdWRpb19mb3JtYXQgJiYKKwkgICAgcGFyYW1zX2Zvcm1hdChwYXJhbXMpID09 IHByaXYtPmF1ZGlvX3NhbXBsZV9mb3JtYXQpIHsKKwkJdGRhOTk4eF9hdWRpb19zdGFydChwcml2 LCAwKTsKKwkJcmV0dXJuIDA7CisJfQorCXByaXYtPnBhcmFtcy5hdWRpb19mb3JtYXQgPSBkYWkt PmlkOworCXByaXYtPmF1ZGlvX3NhbXBsZV9mb3JtYXQgPSBwYXJhbXNfZm9ybWF0KHBhcmFtcyk7 CisJcHJpdi0+cGFyYW1zLmF1ZGlvX2NmZyA9CisJCXByaXYtPmF1ZGlvX3BvcnRzW2RhaS0+aWQg PT0gQUZNVF9JMlMgPyAwIDogMV07CisJdGRhOTk4eF9hdWRpb19zdGFydChwcml2LCAxKTsKKwly ZXR1cm4gMDsKK30KKworc3RhdGljIHZvaWQgdGRhX3NodXRkb3duKHN0cnVjdCBzbmRfcGNtX3N1 YnN0cmVhbSAqc3Vic3RyZWFtLAorCQkJc3RydWN0IHNuZF9zb2NfZGFpICpkYWkpCit7CisJc3Ry dWN0IHRkYTk5OHhfcHJpdiAqcHJpdiA9IHNuZF9zb2NfY29kZWNfZ2V0X2RydmRhdGEoZGFpLT5j b2RlYyk7CisKKwl0ZGE5OTh4X2F1ZGlvX3N0b3AocHJpdik7CisJcHJpdi0+ZGFpX2lkID0gQUZN VF9OT19BVURJTzsKK30KKworc3RhdGljIGNvbnN0IHN0cnVjdCBzbmRfc29jX2RhaV9vcHMgdGRh X29wcyA9IHsKKwkuc3RhcnR1cCA9IHRkYV9zdGFydHVwLAorCS5od19wYXJhbXMgPSB0ZGFfaHdf cGFyYW1zLAorCS5zaHV0ZG93biA9IHRkYV9zaHV0ZG93biwKK307CisKK3N0YXRpYyBzdHJ1Y3Qg c25kX3NvY19kYWlfZHJpdmVyIHRkYTk5OHhfZGFpW10gPSB7CisJeworCQkubmFtZSA9ICJpMnMt aGlmaSIsCisJCS5pZCA9IEFGTVRfSTJTLAorCQkucGxheWJhY2sgPSB7CisJCQkuc3RyZWFtX25h bWUJPSAiSERNSSBJMlMgUGxheWJhY2siLAorCQkJLmNoYW5uZWxzX21pbgk9IDEsCisJCQkuY2hh bm5lbHNfbWF4CT0gOCwKKwkJCS5yYXRlcwkJPSBTTkRSVl9QQ01fUkFURV9DT05USU5VT1VTLAor CQkJLnJhdGVfbWluCT0gNTUxMiwKKwkJCS5yYXRlX21heAk9IDE5MjAwMCwKKwkJCS5mb3JtYXRz CT0gVERBOTk4WF9GT1JNQVRTLAorCQl9LAorCQkub3BzID0gJnRkYV9vcHMsCisJfSwKKwl7CisJ CS5uYW1lID0gInNwZGlmLWhpZmkiLAorCQkuaWQgPSBBRk1UX1NQRElGLAorCQkucGxheWJhY2sg PSB7CisJCQkuc3RyZWFtX25hbWUJPSAiSERNSSBTUERJRiBQbGF5YmFjayIsCisJCQkuY2hhbm5l bHNfbWluCT0gMSwKKwkJCS5jaGFubmVsc19tYXgJPSAyLAorCQkJLnJhdGVzCQk9IFNORFJWX1BD TV9SQVRFX0NPTlRJTlVPVVMsCisJCQkucmF0ZV9taW4JPSAyMjA1MCwKKwkJCS5yYXRlX21heAk9 IDE5MjAwMCwKKwkJCS5mb3JtYXRzCT0gVERBOTk4WF9GT1JNQVRTLAorCQl9LAorCQkub3BzID0g JnRkYV9vcHMsCisJfSwKK307CisKK3N0YXRpYyBjb25zdCBzdHJ1Y3Qgc25kX3NvY19kYXBtX3dp ZGdldCB0ZGFfd2lkZ2V0c1tdID0geworCVNORF9TT0NfREFQTV9PVVRQVVQoImhkbWktb3V0Iiks Cit9Oworc3RhdGljIGNvbnN0IHN0cnVjdCBzbmRfc29jX2RhcG1fcm91dGUgdGRhX3JvdXRlc1td ID0geworCXsgImhkbWktb3V0IiwgTlVMTCwgIkhETUkgSTJTIFBsYXliYWNrIiB9LAorCXsgImhk bWktb3V0IiwgTlVMTCwgIkhETUkgU1BESUYgUGxheWJhY2siIH0sCit9OworCitzdGF0aWMgaW50 IHRkYV9wcm9iZShzdHJ1Y3Qgc25kX3NvY19jb2RlYyAqY29kZWMpCit7CisJc3RydWN0IGkyY19j bGllbnQgKmkyY19jbGllbnQgPSB0b19pMmNfY2xpZW50KGNvZGVjLT5kZXYpOworCXN0cnVjdCB0 ZGE5OTh4X3ByaXYgKnByaXYgPSBpMmNfZ2V0X2NsaWVudGRhdGEoaTJjX2NsaWVudCk7CisJc3Ry dWN0IGRldmljZV9ub2RlICpucCA9IGNvZGVjLT5kZXYtPm9mX25vZGU7CisJaW50IGksIGosIHJl dDsKKwljb25zdCBjaGFyICpwOworCisJaWYgKCFwcml2KQorCQlyZXR1cm4gLUVOT0RFVjsKKwlz bmRfc29jX2NvZGVjX3NldF9kcnZkYXRhKGNvZGVjLCBwcml2KTsKKworCWlmICghbnApCisJCXJl dHVybiAwOworCisJLyogZ2V0IHRoZSBhdWRpbyBpbnB1dCBwb3J0cyovCisJZm9yIChpID0gMDsg aSA8IDI7IGkrKykgeworCQl1MzIgcG9ydDsKKworCQlyZXQgPSBvZl9wcm9wZXJ0eV9yZWFkX3Uz Ml9pbmRleChucCwgImF1ZGlvLXBvcnRzIiwgaSwgJnBvcnQpOworCQlpZiAocmV0KSB7CisJCQlp ZiAoaSA9PSAwKQorCQkJCWRldl9lcnIoY29kZWMtPmRldiwKKwkJCQkJImJhZCBvciBtaXNzaW5n IGF1ZGlvLXBvcnRzXG4iKTsKKwkJCWJyZWFrOworCQl9CisJCXJldCA9IG9mX3Byb3BlcnR5X3Jl YWRfc3RyaW5nX2luZGV4KG5wLCAiYXVkaW8tcG9ydC1uYW1lcyIsCisJCQkJCQlpLCAmcCk7CisJ CWlmIChyZXQpIHsKKwkJCWRldl9lcnIoY29kZWMtPmRldiwKKwkJCQkibWlzc2luZyBhdWRpby1w b3J0LW5hbWVzWyVkXVxuIiwgaSk7CisJCQlicmVhazsKKwkJfQorCQlpZiAoc3RyY21wKHAsICJp MnMiKSA9PSAwKSB7CisJCQlqID0gMDsKKwkJfSBlbHNlIGlmIChzdHJjbXAocCwgInNwZGlmIikg PT0gMCkgeworCQkJaiA9IDE7CisJCX0gZWxzZSB7CisJCQlkZXZfZXJyKGNvZGVjLT5kZXYsCisJ CQkJImJhZCBhdWRpby1wb3J0LW5hbWVzICclcydcbiIsIHApOworCQkJYnJlYWs7CisJCX0KKwkJ cHJpdi0+YXVkaW9fcG9ydHNbal0gPSBwb3J0OworCX0KKwlyZXR1cm4gMDsKK30KKworc3RhdGlj IGNvbnN0IHN0cnVjdCBzbmRfc29jX2NvZGVjX2RyaXZlciBzb2NfY29kZWNfdGRhOTk4eCA9IHsK KwkucHJvYmUgPSB0ZGFfcHJvYmUsCisJLmRhcG1fd2lkZ2V0cyA9IHRkYV93aWRnZXRzLAorCS5u dW1fZGFwbV93aWRnZXRzID0gQVJSQVlfU0laRSh0ZGFfd2lkZ2V0cyksCisJLmRhcG1fcm91dGVz ID0gdGRhX3JvdXRlcywKKwkubnVtX2RhcG1fcm91dGVzID0gQVJSQVlfU0laRSh0ZGFfcm91dGVz KSwKK307CisKK2ludCB0ZGE5OTh4X2NvZGVjX3JlZ2lzdGVyKHN0cnVjdCBkZXZpY2UgKmRldikK K3sKKwlyZXR1cm4gc25kX3NvY19yZWdpc3Rlcl9jb2RlYyhkZXYsCisJCQkJJnNvY19jb2RlY190 ZGE5OTh4LAorCQkJCXRkYTk5OHhfZGFpLCBBUlJBWV9TSVpFKHRkYTk5OHhfZGFpKSk7Cit9CisK K3ZvaWQgdGRhOTk4eF9jb2RlY191bnJlZ2lzdGVyKHN0cnVjdCBkZXZpY2UgKmRldikKK3sKKwlz bmRfc29jX3VucmVnaXN0ZXJfY29kZWMoZGV2KTsKK30KZGlmZiAtLWdpdCBhL2RyaXZlcnMvZ3B1 L2RybS9pMmMvdGRhOTk4eF9kcnYuYyBiL2RyaXZlcnMvZ3B1L2RybS9pMmMvdGRhOTk4eF9kcnYu YwppbmRleCAyNDBjMzMxLi43ZTlmOWRjIDEwMDY0NAotLS0gYS9kcml2ZXJzL2dwdS9kcm0vaTJj L3RkYTk5OHhfZHJ2LmMKKysrIGIvZHJpdmVycy9ncHUvZHJtL2kyYy90ZGE5OTh4X2Rydi5jCkBA IC0yMSw2ICsyMSw3IEBACiAjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+CiAjaW5jbHVkZSA8bGlu dXgvaXJxLmg+CiAjaW5jbHVkZSA8c291bmQvYXNvdW5kZWYuaD4KKyNpbmNsdWRlIDxzb3VuZC9w Y21fcGFyYW1zLmg+CiAKICNpbmNsdWRlIDxkcm0vZHJtUC5oPgogI2luY2x1ZGUgPGRybS9kcm1f Y3J0Y19oZWxwZXIuaD4KQEAgLTI4LDI0ICsyOSw5IEBACiAjaW5jbHVkZSA8ZHJtL2RybV9lZGlk Lmg+CiAjaW5jbHVkZSA8ZHJtL2kyYy90ZGE5OTh4Lmg+CiAKLSNkZWZpbmUgREJHKGZtdCwgLi4u KSBEUk1fREVCVUcoZm10IlxuIiwgIyNfX1ZBX0FSR1NfXykKKyNpbmNsdWRlICJ0ZGE5OTh4X2Ry di5oIgogCi1zdHJ1Y3QgdGRhOTk4eF9wcml2IHsKLQlzdHJ1Y3QgaTJjX2NsaWVudCAqY2VjOwot CXN0cnVjdCBpMmNfY2xpZW50ICpoZG1pOwotCXVpbnQxNl90IHJldjsKLQl1aW50OF90IGN1cnJl bnRfcGFnZTsKLQlpbnQgZHBtczsKLQlib29sIGlzX2hkbWlfc2luazsKLQl1OCB2aXBfY250cmxf MDsKLQl1OCB2aXBfY250cmxfMTsKLQl1OCB2aXBfY250cmxfMjsKLQlzdHJ1Y3QgdGRhOTk4eF9l bmNvZGVyX3BhcmFtcyBwYXJhbXM7Ci0KLQl3YWl0X3F1ZXVlX2hlYWRfdCB3cV9lZGlkOwotCXZv bGF0aWxlIGludCB3cV9lZGlkX3dhaXQ7Ci0Jc3RydWN0IGRybV9lbmNvZGVyICplbmNvZGVyOwot fTsKKyNkZWZpbmUgREJHKGZtdCwgLi4uKSBEUk1fREVCVUcoZm10IlxuIiwgIyNfX1ZBX0FSR1Nf XykKIAogI2RlZmluZSB0b190ZGE5OTh4X3ByaXYoeCkgICgoc3RydWN0IHRkYTk5OHhfcHJpdiAq KXRvX2VuY29kZXJfc2xhdmUoeCktPnNsYXZlX3ByaXYpCiAKQEAgLTY0MCwxMiArNjI2LDExIEBA IHN0YXRpYyB2b2lkCiB0ZGE5OTh4X2NvbmZpZ3VyZV9hdWRpbyhzdHJ1Y3QgdGRhOTk4eF9wcml2 ICpwcml2LAogCQlzdHJ1Y3QgZHJtX2Rpc3BsYXlfbW9kZSAqbW9kZSwgc3RydWN0IHRkYTk5OHhf ZW5jb2Rlcl9wYXJhbXMgKnApCiB7Ci0JdWludDhfdCBidWZbNl0sIGNsa3NlbF9haXAsIGNsa3Nl bF9mcywgY3RzX24sIGFkaXY7CisJdWludDhfdCBidWZbNl0sIGNsa3NlbF9haXAsIGNsa3NlbF9m cywgY3RzX24sIGFkaXYsIGFjbGs7CiAJdWludDMyX3QgbjsKIAogCS8qIEVuYWJsZSBhdWRpbyBw b3J0cyAqLwogCXJlZ193cml0ZShwcml2LCBSRUdfRU5BX0FQLCBwLT5hdWRpb19jZmcpOwotCXJl Z193cml0ZShwcml2LCBSRUdfRU5BX0FDTEssIHAtPmF1ZGlvX2Nsa19jZmcpOwogCiAJLyogU2V0 IGF1ZGlvIGlucHV0IHNvdXJjZSAqLwogCXN3aXRjaCAocC0+YXVkaW9fZm9ybWF0KSB7CkBAIC02 NTQsMTMgKzYzOSwyOCBAQCB0ZGE5OTh4X2NvbmZpZ3VyZV9hdWRpbyhzdHJ1Y3QgdGRhOTk4eF9w cml2ICpwcml2LAogCQljbGtzZWxfYWlwID0gQUlQX0NMS1NFTF9BSVBfU1BESUY7CiAJCWNsa3Nl bF9mcyA9IEFJUF9DTEtTRUxfRlNfRlM2NFNQRElGOwogCQljdHNfbiA9IENUU19OX00oMykgfCBD VFNfTl9LKDMpOworCQlhY2xrID0gMDsJCQkJLyogbm8gY2xvY2sgKi8KIAkJYnJlYWs7CiAKIAlj YXNlIEFGTVRfSTJTOgogCQlyZWdfd3JpdGUocHJpdiwgUkVHX01VWF9BUCwgTVVYX0FQX1NFTEVD VF9JMlMpOwogCQljbGtzZWxfYWlwID0gQUlQX0NMS1NFTF9BSVBfSTJTOwogCQljbGtzZWxfZnMg PSBBSVBfQ0xLU0VMX0ZTX0FDTEs7Ci0JCWN0c19uID0gQ1RTX05fTSgzKSB8IENUU19OX0soMyk7 CisJCS8qIHdpdGggSTJTIGlucHV0LCB0aGUgQ1RTX04gcHJlZGl2aWRlciBkZXBlbmRzIG9uCisJ CSAqIHRoZSBzYW1wbGUgd2lkdGggKi8KKwkJc3dpdGNoIChwcml2LT5hdWRpb19zYW1wbGVfZm9y bWF0KSB7CisJCWNhc2UgU05EUlZfUENNX0ZPUk1BVF9TMTZfTEU6CisJCQljdHNfbiA9IENUU19O X00oMykgfCBDVFNfTl9LKDEpOworCQkJYnJlYWs7CisJCWNhc2UgU05EUlZfUENNX0ZPUk1BVF9T MjRfTEU6CisJCQljdHNfbiA9IENUU19OX00oMykgfCBDVFNfTl9LKDIpOworCQkJYnJlYWs7CisJ CWRlZmF1bHQ6CisJCWNhc2UgU05EUlZfUENNX0ZPUk1BVF9TMzJfTEU6CisJCQljdHNfbiA9IENU U19OX00oMykgfCBDVFNfTl9LKDMpOworCQkJYnJlYWs7CisJCX0KKwkJYWNsayA9IDE7CQkJCS8q IGNsb2NrIGVuYWJsZSAqLwogCQlicmVhazsKIAogCWRlZmF1bHQ6CkBAIC02NzIsNiArNjcyLDcg QEAgdGRhOTk4eF9jb25maWd1cmVfYXVkaW8oc3RydWN0IHRkYTk5OHhfcHJpdiAqcHJpdiwKIAly ZWdfY2xlYXIocHJpdiwgUkVHX0FJUF9DTlRSTF8wLCBBSVBfQ05UUkxfMF9MQVlPVVQgfAogCQkJ CQlBSVBfQ05UUkxfMF9BQ1JfTUFOKTsJLyogYXV0byBDVFMgKi8KIAlyZWdfd3JpdGUocHJpdiwg UkVHX0NUU19OLCBjdHNfbik7CisJcmVnX3dyaXRlKHByaXYsIFJFR19FTkFfQUNMSywgYWNsayk7 CiAKIAkvKgogCSAqIEF1ZGlvIGlucHV0IHNvbWVob3cgZGVwZW5kcyBvbiBIRE1JIGxpbmUgcmF0 ZSB3aGljaCBpcwpAQCAtNzI4LDYgKzcyOSwyNCBAQCB0ZGE5OTh4X2NvbmZpZ3VyZV9hdWRpbyhz dHJ1Y3QgdGRhOTk4eF9wcml2ICpwcml2LAogCXRkYTk5OHhfd3JpdGVfYWlmKHByaXYsIHApOwog fQogCisvKiB0ZGE5OTh4IGNvZGVjIGludGVyZmFjZSAqLwordm9pZCB0ZGE5OTh4X2F1ZGlvX3N0 YXJ0KHN0cnVjdCB0ZGE5OTh4X3ByaXYgKnByaXYsCisJCQkgaW50IGZ1bGwpCit7CisJc3RydWN0 IHRkYTk5OHhfZW5jb2Rlcl9wYXJhbXMgKnAgPSAmcHJpdi0+cGFyYW1zOworCisJaWYgKCFmdWxs KSB7CisJCXJlZ193cml0ZShwcml2LCBSRUdfRU5BX0FQLCBwLT5hdWRpb19jZmcpOworCQlyZXR1 cm47CisJfQorCXRkYTk5OHhfY29uZmlndXJlX2F1ZGlvKHByaXYsICZwcml2LT5lbmNvZGVyLT5j cnRjLT5od21vZGUsIHApOworfQorCit2b2lkIHRkYTk5OHhfYXVkaW9fc3RvcChzdHJ1Y3QgdGRh OTk4eF9wcml2ICpwcml2KQoreworCXJlZ193cml0ZShwcml2LCBSRUdfRU5BX0FQLCAwKTsKK30K KwogLyogRFJNIGVuY29kZXIgZnVuY3Rpb25zICovCiAKIHN0YXRpYyB2b2lkCkBAIC0xMTQ5LDYg KzExNjgsMTEgQEAgdGRhOTk4eF9lbmNvZGVyX2dldF9tb2RlcyhzdHJ1Y3QgZHJtX2VuY29kZXIg KmVuY29kZXIsCiAJCWRybV9tb2RlX2Nvbm5lY3Rvcl91cGRhdGVfZWRpZF9wcm9wZXJ0eShjb25u ZWN0b3IsIGVkaWQpOwogCQluID0gZHJtX2FkZF9lZGlkX21vZGVzKGNvbm5lY3RvciwgZWRpZCk7 CiAJCXByaXYtPmlzX2hkbWlfc2luayA9IGRybV9kZXRlY3RfaGRtaV9tb25pdG9yKGVkaWQpOwor CisJCS8qIGtlZXAgdGhlIEVESUQgYXMgRUxEIGZvciB0aGUgYXVkaW8gc3Vic3lzdGVtICovCisJ CWRybV9lZGlkX3RvX2VsZChjb25uZWN0b3IsIGVkaWQpOworCQlwcml2LT5lbGQgPSBjb25uZWN0 b3ItPmVsZDsKKwogCQlrZnJlZShlZGlkKTsKIAl9CiAKQEAgLTExOTEsNiArMTIxNSw4IEBAIHRk YTk5OHhfZW5jb2Rlcl9kZXN0cm95KHN0cnVjdCBkcm1fZW5jb2RlciAqZW5jb2RlcikKIAlpZiAo cHJpdi0+aGRtaS0+aXJxKQogCQlmcmVlX2lycShwcml2LT5oZG1pLT5pcnEsIHByaXYpOwogCisJ dGRhOTk4eF9jb2RlY191bnJlZ2lzdGVyKCZwcml2LT5oZG1pLT5kZXYpOworCiAJaWYgKHByaXYt PmNlYykKIAkJaTJjX3VucmVnaXN0ZXJfZGV2aWNlKHByaXYtPmNlYyk7CiAJa2ZyZWUocHJpdik7 CkBAIC0xMjM5LDEwICsxMjY1LDE1IEBAIHRkYTk5OHhfZW5jb2Rlcl9pbml0KHN0cnVjdCBpMmNf Y2xpZW50ICpjbGllbnQsCiAJaWYgKCFwcml2KQogCQlyZXR1cm4gLUVOT01FTTsKIAorCWkyY19z ZXRfY2xpZW50ZGF0YShjbGllbnQsIHByaXYpOworCiAJcHJpdi0+dmlwX2NudHJsXzAgPSBWSVBf Q05UUkxfMF9TV0FQX0EoMikgfCBWSVBfQ05UUkxfMF9TV0FQX0IoMyk7CiAJcHJpdi0+dmlwX2Nu dHJsXzEgPSBWSVBfQ05UUkxfMV9TV0FQX0MoMCkgfCBWSVBfQ05UUkxfMV9TV0FQX0QoMSk7CiAJ cHJpdi0+dmlwX2NudHJsXzIgPSBWSVBfQ05UUkxfMl9TV0FQX0UoNCkgfCBWSVBfQ05UUkxfMl9T V0FQX0YoNSk7CiAKKwlwcml2LT5wYXJhbXMuYXVkaW9fZnJhbWVbMV0gPSAxOwkJLyogY2hhbm5l bHMgLSAxICovCisJcHJpdi0+cGFyYW1zLmF1ZGlvX3NhbXBsZV9yYXRlID0gNDgwMDA7CQkvKiA0 OGtIeiAqLworCiAJcHJpdi0+Y3VycmVudF9wYWdlID0gMHhmZjsKIAlwcml2LT5oZG1pID0gY2xp ZW50OwogCXByaXYtPmNlYyA9IGkyY19uZXdfZHVtbXkoY2xpZW50LT5hZGFwdGVyLCAweDM0KTsK QEAgLTEzNDAsNiArMTM3MSw5IEBAIHRkYTk5OHhfZW5jb2Rlcl9pbml0KHN0cnVjdCBpMmNfY2xp ZW50ICpjbGllbnQsCiAJLyogZW5hYmxlIEVESUQgcmVhZCBpcnE6ICovCiAJcmVnX3NldChwcml2 LCBSRUdfSU5UX0ZMQUdTXzIsIElOVF9GTEFHU18yX0VESURfQkxLX1JEKTsKIAorCS8qIHJlZ2lz dGVyIHRoZSBhdWRpbyBDT0RFQyAqLworCXRkYTk5OHhfY29kZWNfcmVnaXN0ZXIoJmNsaWVudC0+ ZGV2KTsKKwogCWlmICghbnApCiAJCXJldHVybiAwOwkJLyogbm9uLURUICovCiAKZGlmZiAtLWdp dCBhL2RyaXZlcnMvZ3B1L2RybS9pMmMvdGRhOTk4eF9kcnYuaCBiL2RyaXZlcnMvZ3B1L2RybS9p MmMvdGRhOTk4eF9kcnYuaApuZXcgZmlsZSBtb2RlIDEwMDY0NAppbmRleCAwMDAwMDAwLi5lNmM4 ZGQ1Ci0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy9ncHUvZHJtL2kyYy90ZGE5OTh4X2Rydi5o CkBAIC0wLDAgKzEsMzIgQEAKKy8qIHRkYTk5OHggcHJpdmF0ZSBkYXRhICovCisKK3N0cnVjdCB0 ZGE5OTh4X3ByaXYgeworCXN0cnVjdCBpMmNfY2xpZW50ICpjZWM7CisJc3RydWN0IGkyY19jbGll bnQgKmhkbWk7CisJdWludDE2X3QgcmV2OworCXVpbnQ4X3QgY3VycmVudF9wYWdlOworCWludCBk cG1zOworCWJvb2wgaXNfaGRtaV9zaW5rOworCXU4IHZpcF9jbnRybF8wOworCXU4IHZpcF9jbnRy bF8xOworCXU4IHZpcF9jbnRybF8yOworCXN0cnVjdCB0ZGE5OTh4X2VuY29kZXJfcGFyYW1zIHBh cmFtczsKKworCXdhaXRfcXVldWVfaGVhZF90IHdxX2VkaWQ7CisJdm9sYXRpbGUgaW50IHdxX2Vk aWRfd2FpdDsKKwlzdHJ1Y3QgZHJtX2VuY29kZXIgKmVuY29kZXI7CisKKwl1OCBhdWRpb19wb3J0 c1syXTsKKwlpbnQgYXVkaW9fc2FtcGxlX2Zvcm1hdDsKKwlpbnQgZGFpX2lkOwkJCS8qIERBSSBJ RCB3aGVuIHN0cmVhbWluZyBhY3RpdmUgKi8KKworCXU4ICplbGQ7CisKKwlzdHJ1Y3Qgc25kX3Bj bV9od19jb25zdHJhaW50X2xpc3QgcmF0ZV9jb25zdHJhaW50czsKK307CisKK2ludCB0ZGE5OTh4 X2NvZGVjX3JlZ2lzdGVyKHN0cnVjdCBkZXZpY2UgKmRldik7Cit2b2lkIHRkYTk5OHhfY29kZWNf dW5yZWdpc3RlcihzdHJ1Y3QgZGV2aWNlICpkZXYpOworCit2b2lkIHRkYTk5OHhfYXVkaW9fc3Rh cnQoc3RydWN0IHRkYTk5OHhfcHJpdiAqcHJpdiwgaW50IGZ1bGwpOwordm9pZCB0ZGE5OTh4X2F1 ZGlvX3N0b3Aoc3RydWN0IHRkYTk5OHhfcHJpdiAqcHJpdik7CmRpZmYgLS1naXQgYS9pbmNsdWRl L2RybS9pMmMvdGRhOTk4eC5oIGIvaW5jbHVkZS9kcm0vaTJjL3RkYTk5OHguaAppbmRleCAzZTQx OWQ5Li4zMTc1N2RmIDEwMDY0NAotLS0gYS9pbmNsdWRlL2RybS9pMmMvdGRhOTk4eC5oCisrKyBi L2luY2x1ZGUvZHJtL2kyYy90ZGE5OTh4LmgKQEAgLTIwLDYgKzIwLDcgQEAgc3RydWN0IHRkYTk5 OHhfZW5jb2Rlcl9wYXJhbXMgewogCXU4IGF1ZGlvX2ZyYW1lWzZdOwogCiAJZW51bSB7CisJCUFG TVRfTk9fQVVESU8gPSAwLAogCQlBRk1UX1NQRElGLAogCQlBRk1UX0kyUwogCX0gYXVkaW9fZm9y bWF0OwotLSAKMi4wLjEKCgoKLS0gCktlbiBhciBjJ2hlbnRhw7EJfAkgICAgICAqKiBCcmVpemgg aGEgTGludXggYXRhdiEgKioKSmVmCQl8CQlodHRwOi8vbW9pbmVqZi5mcmVlLmZyLwpfX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpkcmktZGV2ZWwgbWFpbGlu ZyBsaXN0CmRyaS1kZXZlbEBsaXN0cy5mcmVlZGVza3RvcC5vcmcKaHR0cDovL2xpc3RzLmZyZWVk ZXNrdG9wLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2RyaS1kZXZlbAo= From mboxrd@z Thu Jan 1 00:00:00 1970 From: moinejf@free.fr (Jean-Francois Moine) Date: Fri, 4 Jul 2014 09:17:33 +0200 Subject: [PATCH v2] ASoC: tda998x: add a codec to the HDMI transmitter Message-ID: <20140704091733.10258cfe@armhf> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org This patch adds a CODEC function to the NXP TDA998x HDMI transmitter. The CODEC handles both I2S and S/PDIF input and does dynamic input switch in the TDA998x I2C driver on start/stop audio streaming. Signed-off-by: Jean-Francois Moine --- v2: check double stream start (Mark Brown) --- .../devicetree/bindings/drm/i2c/tda998x.txt | 13 ++ drivers/gpu/drm/i2c/Makefile | 2 +- drivers/gpu/drm/i2c/tda998x_codec.c | 247 +++++++++++++++++++++ drivers/gpu/drm/i2c/tda998x_drv.c | 74 ++++-- drivers/gpu/drm/i2c/tda998x_drv.h | 32 +++ include/drm/i2c/tda998x.h | 1 + 6 files changed, 348 insertions(+), 21 deletions(-) create mode 100644 drivers/gpu/drm/i2c/tda998x_codec.c create mode 100644 drivers/gpu/drm/i2c/tda998x_drv.h diff --git a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt index d7df01c..7ce4eac 100644 --- a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt +++ b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt @@ -15,6 +15,15 @@ Optional properties: - video-ports: 24 bits value which defines how the video controller output is wired to the TDA998x input - default: <0x230145> + - audio-ports: one or two values corresponding to entries in + the audio-port-names property. + + - audio-port-names: must contain "i2s", "spdif" entries + matching entries in the audio-ports property. + + - #sound-dai-cells: must be set to <1> for use with the simple-card. + The DAI 0 is the I2S input and the DAI 1 is the S/PDIF input. + Example: tda998x: hdmi-encoder { @@ -24,4 +33,8 @@ Example: interrupts = <27 2>; /* falling edge */ pinctrl-0 = <&pmx_camera>; pinctrl-names = "default"; + + audio-ports = <0x03>, <0x04>; + audio-port-names = "i2s", "spdif"; + #sound-dai-cells = <1>; }; diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile index 43aa33b..f2d625c 100644 --- a/drivers/gpu/drm/i2c/Makefile +++ b/drivers/gpu/drm/i2c/Makefile @@ -6,5 +6,5 @@ obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o sil164-y := sil164_drv.o obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o -tda998x-y := tda998x_drv.o +tda998x-y := tda998x_drv.o tda998x_codec.o obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o diff --git a/drivers/gpu/drm/i2c/tda998x_codec.c b/drivers/gpu/drm/i2c/tda998x_codec.c new file mode 100644 index 0000000..e22f974 --- /dev/null +++ b/drivers/gpu/drm/i2c/tda998x_codec.c @@ -0,0 +1,247 @@ +/* + * ALSA SoC TDA998X CODEC + * + * Copyright (C) 2014 Jean-Francois Moine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tda998x_drv.h" + +#define TDA998X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static int tda_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tda998x_priv *priv = snd_soc_codec_get_drvdata(dai->codec); + u8 *eld = priv->eld; + struct snd_pcm_runtime *runtime = substream->runtime; + u8 *sad; + int sad_count; + unsigned eld_ver, mnl, rate_mask; + unsigned max_channels, fmt; + u64 formats; + struct snd_pcm_hw_constraint_list *rate_constraints = + &priv->rate_constraints; + static const u32 hdmi_rates[] = { + 32000, 44100, 48000, 88200, 9600, 176400, 192000 + }; + + /* check if streaming is already active */ + if (priv->dai_id != AFMT_NO_AUDIO) + return -EBUSY; + priv->dai_id = dai->id; + + if (!eld) + return 0; + + /* adjust the hw params from the ELD (EDID) */ + eld_ver = eld[0] >> 3; + if (eld_ver != 2 && eld_ver != 31) + return 0; + + mnl = eld[4] & 0x1f; + if (mnl > 16) + return 0; + + sad_count = eld[5] >> 4; + sad = eld + 20 + mnl; + + /* Start from the basic audio settings */ + max_channels = 2; + rate_mask = 0; + fmt = 0; + while (sad_count--) { + switch (sad[0] & 0x78) { + case 0x08: /* PCM */ + max_channels = max(max_channels, (sad[0] & 7) + 1u); + rate_mask |= sad[1]; + fmt |= sad[2] & 0x07; + break; + } + sad += 3; + } + + /* set the constraints */ + rate_constraints->list = hdmi_rates; + rate_constraints->count = ARRAY_SIZE(hdmi_rates); + rate_constraints->mask = rate_mask; + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + rate_constraints); + + formats = 0; + if (fmt & 1) + formats |= SNDRV_PCM_FMTBIT_S16_LE; + if (fmt & 2) + formats |= SNDRV_PCM_FMTBIT_S20_3LE; + if (fmt & 4) + formats |= SNDRV_PCM_FMTBIT_S24_LE; + snd_pcm_hw_constraint_mask64(runtime, + SNDRV_PCM_HW_PARAM_FORMAT, + formats); + + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + 1, max_channels); + return 0; +} + +static int tda_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tda998x_priv *priv = snd_soc_codec_get_drvdata(dai->codec); + + /* Requires an attached display */ + if (!priv->encoder->crtc) + return -ENODEV; + + /* if same input and same parameters, do not do a full switch */ + if (dai->id == priv->params.audio_format && + params_format(params) == priv->audio_sample_format) { + tda998x_audio_start(priv, 0); + return 0; + } + priv->params.audio_format = dai->id; + priv->audio_sample_format = params_format(params); + priv->params.audio_cfg = + priv->audio_ports[dai->id == AFMT_I2S ? 0 : 1]; + tda998x_audio_start(priv, 1); + return 0; +} + +static void tda_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tda998x_priv *priv = snd_soc_codec_get_drvdata(dai->codec); + + tda998x_audio_stop(priv); + priv->dai_id = AFMT_NO_AUDIO; +} + +static const struct snd_soc_dai_ops tda_ops = { + .startup = tda_startup, + .hw_params = tda_hw_params, + .shutdown = tda_shutdown, +}; + +static struct snd_soc_dai_driver tda998x_dai[] = { + { + .name = "i2s-hifi", + .id = AFMT_I2S, + .playback = { + .stream_name = "HDMI I2S Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 192000, + .formats = TDA998X_FORMATS, + }, + .ops = &tda_ops, + }, + { + .name = "spdif-hifi", + .id = AFMT_SPDIF, + .playback = { + .stream_name = "HDMI SPDIF Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 22050, + .rate_max = 192000, + .formats = TDA998X_FORMATS, + }, + .ops = &tda_ops, + }, +}; + +static const struct snd_soc_dapm_widget tda_widgets[] = { + SND_SOC_DAPM_OUTPUT("hdmi-out"), +}; +static const struct snd_soc_dapm_route tda_routes[] = { + { "hdmi-out", NULL, "HDMI I2S Playback" }, + { "hdmi-out", NULL, "HDMI SPDIF Playback" }, +}; + +static int tda_probe(struct snd_soc_codec *codec) +{ + struct i2c_client *i2c_client = to_i2c_client(codec->dev); + struct tda998x_priv *priv = i2c_get_clientdata(i2c_client); + struct device_node *np = codec->dev->of_node; + int i, j, ret; + const char *p; + + if (!priv) + return -ENODEV; + snd_soc_codec_set_drvdata(codec, priv); + + if (!np) + return 0; + + /* get the audio input ports*/ + for (i = 0; i < 2; i++) { + u32 port; + + ret = of_property_read_u32_index(np, "audio-ports", i, &port); + if (ret) { + if (i == 0) + dev_err(codec->dev, + "bad or missing audio-ports\n"); + break; + } + ret = of_property_read_string_index(np, "audio-port-names", + i, &p); + if (ret) { + dev_err(codec->dev, + "missing audio-port-names[%d]\n", i); + break; + } + if (strcmp(p, "i2s") == 0) { + j = 0; + } else if (strcmp(p, "spdif") == 0) { + j = 1; + } else { + dev_err(codec->dev, + "bad audio-port-names '%s'\n", p); + break; + } + priv->audio_ports[j] = port; + } + return 0; +} + +static const struct snd_soc_codec_driver soc_codec_tda998x = { + .probe = tda_probe, + .dapm_widgets = tda_widgets, + .num_dapm_widgets = ARRAY_SIZE(tda_widgets), + .dapm_routes = tda_routes, + .num_dapm_routes = ARRAY_SIZE(tda_routes), +}; + +int tda998x_codec_register(struct device *dev) +{ + return snd_soc_register_codec(dev, + &soc_codec_tda998x, + tda998x_dai, ARRAY_SIZE(tda998x_dai)); +} + +void tda998x_codec_unregister(struct device *dev) +{ + snd_soc_unregister_codec(dev); +} diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 240c331..7e9f9dc 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -28,24 +29,9 @@ #include #include -#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) +#include "tda998x_drv.h" -struct tda998x_priv { - struct i2c_client *cec; - struct i2c_client *hdmi; - uint16_t rev; - uint8_t current_page; - int dpms; - bool is_hdmi_sink; - u8 vip_cntrl_0; - u8 vip_cntrl_1; - u8 vip_cntrl_2; - struct tda998x_encoder_params params; - - wait_queue_head_t wq_edid; - volatile int wq_edid_wait; - struct drm_encoder *encoder; -}; +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) #define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv) @@ -640,12 +626,11 @@ static void tda998x_configure_audio(struct tda998x_priv *priv, struct drm_display_mode *mode, struct tda998x_encoder_params *p) { - uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv; + uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv, aclk; uint32_t n; /* Enable audio ports */ reg_write(priv, REG_ENA_AP, p->audio_cfg); - reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg); /* Set audio input source */ switch (p->audio_format) { @@ -654,13 +639,28 @@ tda998x_configure_audio(struct tda998x_priv *priv, clksel_aip = AIP_CLKSEL_AIP_SPDIF; clksel_fs = AIP_CLKSEL_FS_FS64SPDIF; cts_n = CTS_N_M(3) | CTS_N_K(3); + aclk = 0; /* no clock */ break; case AFMT_I2S: reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); clksel_aip = AIP_CLKSEL_AIP_I2S; clksel_fs = AIP_CLKSEL_FS_ACLK; - cts_n = CTS_N_M(3) | CTS_N_K(3); + /* with I2S input, the CTS_N predivider depends on + * the sample width */ + switch (priv->audio_sample_format) { + case SNDRV_PCM_FORMAT_S16_LE: + cts_n = CTS_N_M(3) | CTS_N_K(1); + break; + case SNDRV_PCM_FORMAT_S24_LE: + cts_n = CTS_N_M(3) | CTS_N_K(2); + break; + default: + case SNDRV_PCM_FORMAT_S32_LE: + cts_n = CTS_N_M(3) | CTS_N_K(3); + break; + } + aclk = 1; /* clock enable */ break; default: @@ -672,6 +672,7 @@ tda998x_configure_audio(struct tda998x_priv *priv, reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT | AIP_CNTRL_0_ACR_MAN); /* auto CTS */ reg_write(priv, REG_CTS_N, cts_n); + reg_write(priv, REG_ENA_ACLK, aclk); /* * Audio input somehow depends on HDMI line rate which is @@ -728,6 +729,24 @@ tda998x_configure_audio(struct tda998x_priv *priv, tda998x_write_aif(priv, p); } +/* tda998x codec interface */ +void tda998x_audio_start(struct tda998x_priv *priv, + int full) +{ + struct tda998x_encoder_params *p = &priv->params; + + if (!full) { + reg_write(priv, REG_ENA_AP, p->audio_cfg); + return; + } + tda998x_configure_audio(priv, &priv->encoder->crtc->hwmode, p); +} + +void tda998x_audio_stop(struct tda998x_priv *priv) +{ + reg_write(priv, REG_ENA_AP, 0); +} + /* DRM encoder functions */ static void @@ -1149,6 +1168,11 @@ tda998x_encoder_get_modes(struct drm_encoder *encoder, drm_mode_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); + + /* keep the EDID as ELD for the audio subsystem */ + drm_edid_to_eld(connector, edid); + priv->eld = connector->eld; + kfree(edid); } @@ -1191,6 +1215,8 @@ tda998x_encoder_destroy(struct drm_encoder *encoder) if (priv->hdmi->irq) free_irq(priv->hdmi->irq, priv); + tda998x_codec_unregister(&priv->hdmi->dev); + if (priv->cec) i2c_unregister_device(priv->cec); kfree(priv); @@ -1239,10 +1265,15 @@ tda998x_encoder_init(struct i2c_client *client, if (!priv) return -ENOMEM; + i2c_set_clientdata(client, priv); + priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3); priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5); + priv->params.audio_frame[1] = 1; /* channels - 1 */ + priv->params.audio_sample_rate = 48000; /* 48kHz */ + priv->current_page = 0xff; priv->hdmi = client; priv->cec = i2c_new_dummy(client->adapter, 0x34); @@ -1340,6 +1371,9 @@ tda998x_encoder_init(struct i2c_client *client, /* enable EDID read irq: */ reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); + /* register the audio CODEC */ + tda998x_codec_register(&client->dev); + if (!np) return 0; /* non-DT */ diff --git a/drivers/gpu/drm/i2c/tda998x_drv.h b/drivers/gpu/drm/i2c/tda998x_drv.h new file mode 100644 index 0000000..e6c8dd5 --- /dev/null +++ b/drivers/gpu/drm/i2c/tda998x_drv.h @@ -0,0 +1,32 @@ +/* tda998x private data */ + +struct tda998x_priv { + struct i2c_client *cec; + struct i2c_client *hdmi; + uint16_t rev; + uint8_t current_page; + int dpms; + bool is_hdmi_sink; + u8 vip_cntrl_0; + u8 vip_cntrl_1; + u8 vip_cntrl_2; + struct tda998x_encoder_params params; + + wait_queue_head_t wq_edid; + volatile int wq_edid_wait; + struct drm_encoder *encoder; + + u8 audio_ports[2]; + int audio_sample_format; + int dai_id; /* DAI ID when streaming active */ + + u8 *eld; + + struct snd_pcm_hw_constraint_list rate_constraints; +}; + +int tda998x_codec_register(struct device *dev); +void tda998x_codec_unregister(struct device *dev); + +void tda998x_audio_start(struct tda998x_priv *priv, int full); +void tda998x_audio_stop(struct tda998x_priv *priv); diff --git a/include/drm/i2c/tda998x.h b/include/drm/i2c/tda998x.h index 3e419d9..31757df 100644 --- a/include/drm/i2c/tda998x.h +++ b/include/drm/i2c/tda998x.h @@ -20,6 +20,7 @@ struct tda998x_encoder_params { u8 audio_frame[6]; enum { + AFMT_NO_AUDIO = 0, AFMT_SPDIF, AFMT_I2S } audio_format; -- 2.0.1 -- Ken ar c'henta? | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/ From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751987AbaGDHPk (ORCPT ); Fri, 4 Jul 2014 03:15:40 -0400 Received: from smtp1-g21.free.fr ([212.27.42.1]:39860 "EHLO smtp1-g21.free.fr" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750957AbaGDHPi convert rfc822-to-8bit (ORCPT ); Fri, 4 Jul 2014 03:15:38 -0400 Date: Fri, 4 Jul 2014 09:17:33 +0200 From: Jean-Francois Moine To: Mark Brown , Russell King - ARM Linux Cc: alsa-devel@alsa-project.org, lgirdwood@gmail.com, dri-devel@lists.freedesktop.org, Rob Clark , linux-arm-kernel@lists.infradead.org, Dave Airlie , linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Subject: [PATCH v2] ASoC: tda998x: add a codec to the HDMI transmitter Message-ID: <20140704091733.10258cfe@armhf> X-Mailer: Claws Mail 3.10.1 (GTK+ 2.24.24; arm-unknown-linux-gnueabihf) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8BIT Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds a CODEC function to the NXP TDA998x HDMI transmitter. The CODEC handles both I2S and S/PDIF input and does dynamic input switch in the TDA998x I2C driver on start/stop audio streaming. Signed-off-by: Jean-Francois Moine --- v2: check double stream start (Mark Brown) --- .../devicetree/bindings/drm/i2c/tda998x.txt | 13 ++ drivers/gpu/drm/i2c/Makefile | 2 +- drivers/gpu/drm/i2c/tda998x_codec.c | 247 +++++++++++++++++++++ drivers/gpu/drm/i2c/tda998x_drv.c | 74 ++++-- drivers/gpu/drm/i2c/tda998x_drv.h | 32 +++ include/drm/i2c/tda998x.h | 1 + 6 files changed, 348 insertions(+), 21 deletions(-) create mode 100644 drivers/gpu/drm/i2c/tda998x_codec.c create mode 100644 drivers/gpu/drm/i2c/tda998x_drv.h diff --git a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt index d7df01c..7ce4eac 100644 --- a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt +++ b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt @@ -15,6 +15,15 @@ Optional properties: - video-ports: 24 bits value which defines how the video controller output is wired to the TDA998x input - default: <0x230145> + - audio-ports: one or two values corresponding to entries in + the audio-port-names property. + + - audio-port-names: must contain "i2s", "spdif" entries + matching entries in the audio-ports property. + + - #sound-dai-cells: must be set to <1> for use with the simple-card. + The DAI 0 is the I2S input and the DAI 1 is the S/PDIF input. + Example: tda998x: hdmi-encoder { @@ -24,4 +33,8 @@ Example: interrupts = <27 2>; /* falling edge */ pinctrl-0 = <&pmx_camera>; pinctrl-names = "default"; + + audio-ports = <0x03>, <0x04>; + audio-port-names = "i2s", "spdif"; + #sound-dai-cells = <1>; }; diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile index 43aa33b..f2d625c 100644 --- a/drivers/gpu/drm/i2c/Makefile +++ b/drivers/gpu/drm/i2c/Makefile @@ -6,5 +6,5 @@ obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o sil164-y := sil164_drv.o obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o -tda998x-y := tda998x_drv.o +tda998x-y := tda998x_drv.o tda998x_codec.o obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o diff --git a/drivers/gpu/drm/i2c/tda998x_codec.c b/drivers/gpu/drm/i2c/tda998x_codec.c new file mode 100644 index 0000000..e22f974 --- /dev/null +++ b/drivers/gpu/drm/i2c/tda998x_codec.c @@ -0,0 +1,247 @@ +/* + * ALSA SoC TDA998X CODEC + * + * Copyright (C) 2014 Jean-Francois Moine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tda998x_drv.h" + +#define TDA998X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static int tda_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tda998x_priv *priv = snd_soc_codec_get_drvdata(dai->codec); + u8 *eld = priv->eld; + struct snd_pcm_runtime *runtime = substream->runtime; + u8 *sad; + int sad_count; + unsigned eld_ver, mnl, rate_mask; + unsigned max_channels, fmt; + u64 formats; + struct snd_pcm_hw_constraint_list *rate_constraints = + &priv->rate_constraints; + static const u32 hdmi_rates[] = { + 32000, 44100, 48000, 88200, 9600, 176400, 192000 + }; + + /* check if streaming is already active */ + if (priv->dai_id != AFMT_NO_AUDIO) + return -EBUSY; + priv->dai_id = dai->id; + + if (!eld) + return 0; + + /* adjust the hw params from the ELD (EDID) */ + eld_ver = eld[0] >> 3; + if (eld_ver != 2 && eld_ver != 31) + return 0; + + mnl = eld[4] & 0x1f; + if (mnl > 16) + return 0; + + sad_count = eld[5] >> 4; + sad = eld + 20 + mnl; + + /* Start from the basic audio settings */ + max_channels = 2; + rate_mask = 0; + fmt = 0; + while (sad_count--) { + switch (sad[0] & 0x78) { + case 0x08: /* PCM */ + max_channels = max(max_channels, (sad[0] & 7) + 1u); + rate_mask |= sad[1]; + fmt |= sad[2] & 0x07; + break; + } + sad += 3; + } + + /* set the constraints */ + rate_constraints->list = hdmi_rates; + rate_constraints->count = ARRAY_SIZE(hdmi_rates); + rate_constraints->mask = rate_mask; + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + rate_constraints); + + formats = 0; + if (fmt & 1) + formats |= SNDRV_PCM_FMTBIT_S16_LE; + if (fmt & 2) + formats |= SNDRV_PCM_FMTBIT_S20_3LE; + if (fmt & 4) + formats |= SNDRV_PCM_FMTBIT_S24_LE; + snd_pcm_hw_constraint_mask64(runtime, + SNDRV_PCM_HW_PARAM_FORMAT, + formats); + + snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, + 1, max_channels); + return 0; +} + +static int tda_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct tda998x_priv *priv = snd_soc_codec_get_drvdata(dai->codec); + + /* Requires an attached display */ + if (!priv->encoder->crtc) + return -ENODEV; + + /* if same input and same parameters, do not do a full switch */ + if (dai->id == priv->params.audio_format && + params_format(params) == priv->audio_sample_format) { + tda998x_audio_start(priv, 0); + return 0; + } + priv->params.audio_format = dai->id; + priv->audio_sample_format = params_format(params); + priv->params.audio_cfg = + priv->audio_ports[dai->id == AFMT_I2S ? 0 : 1]; + tda998x_audio_start(priv, 1); + return 0; +} + +static void tda_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct tda998x_priv *priv = snd_soc_codec_get_drvdata(dai->codec); + + tda998x_audio_stop(priv); + priv->dai_id = AFMT_NO_AUDIO; +} + +static const struct snd_soc_dai_ops tda_ops = { + .startup = tda_startup, + .hw_params = tda_hw_params, + .shutdown = tda_shutdown, +}; + +static struct snd_soc_dai_driver tda998x_dai[] = { + { + .name = "i2s-hifi", + .id = AFMT_I2S, + .playback = { + .stream_name = "HDMI I2S Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5512, + .rate_max = 192000, + .formats = TDA998X_FORMATS, + }, + .ops = &tda_ops, + }, + { + .name = "spdif-hifi", + .id = AFMT_SPDIF, + .playback = { + .stream_name = "HDMI SPDIF Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 22050, + .rate_max = 192000, + .formats = TDA998X_FORMATS, + }, + .ops = &tda_ops, + }, +}; + +static const struct snd_soc_dapm_widget tda_widgets[] = { + SND_SOC_DAPM_OUTPUT("hdmi-out"), +}; +static const struct snd_soc_dapm_route tda_routes[] = { + { "hdmi-out", NULL, "HDMI I2S Playback" }, + { "hdmi-out", NULL, "HDMI SPDIF Playback" }, +}; + +static int tda_probe(struct snd_soc_codec *codec) +{ + struct i2c_client *i2c_client = to_i2c_client(codec->dev); + struct tda998x_priv *priv = i2c_get_clientdata(i2c_client); + struct device_node *np = codec->dev->of_node; + int i, j, ret; + const char *p; + + if (!priv) + return -ENODEV; + snd_soc_codec_set_drvdata(codec, priv); + + if (!np) + return 0; + + /* get the audio input ports*/ + for (i = 0; i < 2; i++) { + u32 port; + + ret = of_property_read_u32_index(np, "audio-ports", i, &port); + if (ret) { + if (i == 0) + dev_err(codec->dev, + "bad or missing audio-ports\n"); + break; + } + ret = of_property_read_string_index(np, "audio-port-names", + i, &p); + if (ret) { + dev_err(codec->dev, + "missing audio-port-names[%d]\n", i); + break; + } + if (strcmp(p, "i2s") == 0) { + j = 0; + } else if (strcmp(p, "spdif") == 0) { + j = 1; + } else { + dev_err(codec->dev, + "bad audio-port-names '%s'\n", p); + break; + } + priv->audio_ports[j] = port; + } + return 0; +} + +static const struct snd_soc_codec_driver soc_codec_tda998x = { + .probe = tda_probe, + .dapm_widgets = tda_widgets, + .num_dapm_widgets = ARRAY_SIZE(tda_widgets), + .dapm_routes = tda_routes, + .num_dapm_routes = ARRAY_SIZE(tda_routes), +}; + +int tda998x_codec_register(struct device *dev) +{ + return snd_soc_register_codec(dev, + &soc_codec_tda998x, + tda998x_dai, ARRAY_SIZE(tda998x_dai)); +} + +void tda998x_codec_unregister(struct device *dev) +{ + snd_soc_unregister_codec(dev); +} diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 240c331..7e9f9dc 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -28,24 +29,9 @@ #include #include -#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) +#include "tda998x_drv.h" -struct tda998x_priv { - struct i2c_client *cec; - struct i2c_client *hdmi; - uint16_t rev; - uint8_t current_page; - int dpms; - bool is_hdmi_sink; - u8 vip_cntrl_0; - u8 vip_cntrl_1; - u8 vip_cntrl_2; - struct tda998x_encoder_params params; - - wait_queue_head_t wq_edid; - volatile int wq_edid_wait; - struct drm_encoder *encoder; -}; +#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) #define to_tda998x_priv(x) ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv) @@ -640,12 +626,11 @@ static void tda998x_configure_audio(struct tda998x_priv *priv, struct drm_display_mode *mode, struct tda998x_encoder_params *p) { - uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv; + uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv, aclk; uint32_t n; /* Enable audio ports */ reg_write(priv, REG_ENA_AP, p->audio_cfg); - reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg); /* Set audio input source */ switch (p->audio_format) { @@ -654,13 +639,28 @@ tda998x_configure_audio(struct tda998x_priv *priv, clksel_aip = AIP_CLKSEL_AIP_SPDIF; clksel_fs = AIP_CLKSEL_FS_FS64SPDIF; cts_n = CTS_N_M(3) | CTS_N_K(3); + aclk = 0; /* no clock */ break; case AFMT_I2S: reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); clksel_aip = AIP_CLKSEL_AIP_I2S; clksel_fs = AIP_CLKSEL_FS_ACLK; - cts_n = CTS_N_M(3) | CTS_N_K(3); + /* with I2S input, the CTS_N predivider depends on + * the sample width */ + switch (priv->audio_sample_format) { + case SNDRV_PCM_FORMAT_S16_LE: + cts_n = CTS_N_M(3) | CTS_N_K(1); + break; + case SNDRV_PCM_FORMAT_S24_LE: + cts_n = CTS_N_M(3) | CTS_N_K(2); + break; + default: + case SNDRV_PCM_FORMAT_S32_LE: + cts_n = CTS_N_M(3) | CTS_N_K(3); + break; + } + aclk = 1; /* clock enable */ break; default: @@ -672,6 +672,7 @@ tda998x_configure_audio(struct tda998x_priv *priv, reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT | AIP_CNTRL_0_ACR_MAN); /* auto CTS */ reg_write(priv, REG_CTS_N, cts_n); + reg_write(priv, REG_ENA_ACLK, aclk); /* * Audio input somehow depends on HDMI line rate which is @@ -728,6 +729,24 @@ tda998x_configure_audio(struct tda998x_priv *priv, tda998x_write_aif(priv, p); } +/* tda998x codec interface */ +void tda998x_audio_start(struct tda998x_priv *priv, + int full) +{ + struct tda998x_encoder_params *p = &priv->params; + + if (!full) { + reg_write(priv, REG_ENA_AP, p->audio_cfg); + return; + } + tda998x_configure_audio(priv, &priv->encoder->crtc->hwmode, p); +} + +void tda998x_audio_stop(struct tda998x_priv *priv) +{ + reg_write(priv, REG_ENA_AP, 0); +} + /* DRM encoder functions */ static void @@ -1149,6 +1168,11 @@ tda998x_encoder_get_modes(struct drm_encoder *encoder, drm_mode_connector_update_edid_property(connector, edid); n = drm_add_edid_modes(connector, edid); priv->is_hdmi_sink = drm_detect_hdmi_monitor(edid); + + /* keep the EDID as ELD for the audio subsystem */ + drm_edid_to_eld(connector, edid); + priv->eld = connector->eld; + kfree(edid); } @@ -1191,6 +1215,8 @@ tda998x_encoder_destroy(struct drm_encoder *encoder) if (priv->hdmi->irq) free_irq(priv->hdmi->irq, priv); + tda998x_codec_unregister(&priv->hdmi->dev); + if (priv->cec) i2c_unregister_device(priv->cec); kfree(priv); @@ -1239,10 +1265,15 @@ tda998x_encoder_init(struct i2c_client *client, if (!priv) return -ENOMEM; + i2c_set_clientdata(client, priv); + priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3); priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5); + priv->params.audio_frame[1] = 1; /* channels - 1 */ + priv->params.audio_sample_rate = 48000; /* 48kHz */ + priv->current_page = 0xff; priv->hdmi = client; priv->cec = i2c_new_dummy(client->adapter, 0x34); @@ -1340,6 +1371,9 @@ tda998x_encoder_init(struct i2c_client *client, /* enable EDID read irq: */ reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); + /* register the audio CODEC */ + tda998x_codec_register(&client->dev); + if (!np) return 0; /* non-DT */ diff --git a/drivers/gpu/drm/i2c/tda998x_drv.h b/drivers/gpu/drm/i2c/tda998x_drv.h new file mode 100644 index 0000000..e6c8dd5 --- /dev/null +++ b/drivers/gpu/drm/i2c/tda998x_drv.h @@ -0,0 +1,32 @@ +/* tda998x private data */ + +struct tda998x_priv { + struct i2c_client *cec; + struct i2c_client *hdmi; + uint16_t rev; + uint8_t current_page; + int dpms; + bool is_hdmi_sink; + u8 vip_cntrl_0; + u8 vip_cntrl_1; + u8 vip_cntrl_2; + struct tda998x_encoder_params params; + + wait_queue_head_t wq_edid; + volatile int wq_edid_wait; + struct drm_encoder *encoder; + + u8 audio_ports[2]; + int audio_sample_format; + int dai_id; /* DAI ID when streaming active */ + + u8 *eld; + + struct snd_pcm_hw_constraint_list rate_constraints; +}; + +int tda998x_codec_register(struct device *dev); +void tda998x_codec_unregister(struct device *dev); + +void tda998x_audio_start(struct tda998x_priv *priv, int full); +void tda998x_audio_stop(struct tda998x_priv *priv); diff --git a/include/drm/i2c/tda998x.h b/include/drm/i2c/tda998x.h index 3e419d9..31757df 100644 --- a/include/drm/i2c/tda998x.h +++ b/include/drm/i2c/tda998x.h @@ -20,6 +20,7 @@ struct tda998x_encoder_params { u8 audio_frame[6]; enum { + AFMT_NO_AUDIO = 0, AFMT_SPDIF, AFMT_I2S } audio_format; -- 2.0.1 -- Ken ar c'hentaƱ | ** Breizh ha Linux atav! ** Jef | http://moinejf.free.fr/