* [PATCH V1] TAOS tsl2x7x @ 2012-02-10 19:06 Jon Brenner 2012-02-13 15:19 ` Jonathan Cameron 0 siblings, 1 reply; 3+ messages in thread From: Jon Brenner @ 2012-02-10 19:06 UTC (permalink / raw) To: Jonathan Cameron; +Cc: linux-kernel, linux-iio VEFPUyBkZXZpY2UgZHJpdmVyIGZvciB0c2wvdG1kIDI3NzEgYW5kIDI3NzIgZGV2aWNlIGZhbWls aWVzIChpbmMgYWxsIHZhcmlhbnRzKS4NCg0KU2lnbmVkLW9mZi1ieTogSm9uIEJyZW5uZXIgPGpi cmVubmVyQHRhb3NpbmMuY29tPg0KDQotLS0NCiAuLi4vaWlvL0RvY3VtZW50YXRpb24vc3lzZnMt YnVzLWlpby1saWdodC10c2wyeDd4ICB8ICAgNzEgKw0KIGRyaXZlcnMvc3RhZ2luZy9paW8vbGln aHQvS2NvbmZpZyAgICAgICAgICAgICAgICAgIHwgICAxMSArDQogZHJpdmVycy9zdGFnaW5nL2lp by9saWdodC9NYWtlZmlsZSAgICAgICAgICAgICAgICAgfCAgICAxICsNCiBkcml2ZXJzL3N0YWdp bmcvaWlvL2xpZ2h0L3RzbDJ4N3hfY29yZS5jICAgICAgICAgICB8IDIwNTMgKysrKysrKysrKysr KysrKysrKysNCiBkcml2ZXJzL3N0YWdpbmcvaWlvL2xpZ2h0L3RzbDJ4N3hfY29yZS5oICAgICAg ICAgICB8ICAxMzggKysNCiA1IGZpbGVzIGNoYW5nZWQsIDIyNzQgaW5zZXJ0aW9ucygrKSwgMCBk ZWxldGlvbnMoLSkNCg0KZGlmZiAtLWdpdCBhL2RyaXZlcnMvc3RhZ2luZy9paW8vRG9jdW1lbnRh dGlvbi9zeXNmcy1idXMtaWlvLWxpZ2h0LXRzbDJ4N3ggYi9kcml2ZXJzL3N0YWdpbmcvaWlvL0Rv Y3VtZW50YXRpb24vc3lzZnMtYnVzLWlpby1saWdodC10c2wyeDd4DQpuZXcgZmlsZSBtb2RlIDEw MDY0NA0KaW5kZXggMDAwMDAwMC4uZjFiYjVmNQ0KLS0tIC9kZXYvbnVsbA0KKysrIGIvZHJpdmVy cy9zdGFnaW5nL2lpby9Eb2N1bWVudGF0aW9uL3N5c2ZzLWJ1cy1paW8tbGlnaHQtdHNsMng3eA0K QEAgLTAsMCArMSw3MSBAQA0KK1doYXQ6CQkvc3lzL2J1cy9paW8vZGV2aWNlcy9kZXZpY2Vbbl0v bHV4X3RhYmxlDQorS2VybmVsVmVyc2lvbjoJMi42LjM3DQorQ29udGFjdDoJbGludXgtaWlvQHZn ZXIua2VybmVsLm9yZw0KK0Rlc2NyaXB0aW9uOg0KKwkJVGhpcyBwcm9wZXJ0eSBnZXRzL3NldHMg dGhlIHRhYmxlIG9mIGNvZWZmaWNpZW50cw0KKwkJdXNlZCBpbiBjYWxjdWxhdGluZyBpbGx1bWlu YW5jZSBpbiBsdXguDQorDQorV2hhdDoJCS9zeXMvYnVzL2lpby9kZXZpY2VzL2RldmljZVtuXS9p bGx1bWluYW5jZTBfY2FsaWJyYXRlDQorS2VybmVsVmVyc2lvbjoJMi42LjM3DQorQ29udGFjdDoJ bGludXgtaWlvQHZnZXIua2VybmVsLm9yZw0KK0Rlc2NyaXB0aW9uOg0KKwkJVGhpcyBwcm9wZXJ0 eSBjYXVzZXMgYW4gaW50ZXJuYWwgY2FsaWJyYXRpb24gb2YgdGhlIGFscyBnYWluIHRyaW0NCisJ CXZhbHVlIHdoaWNoIGlzIGxhdGVyIHVzZWQgaW4gY2FsY3VsYXRpbmcgaWxsdW1pbmFuY2UgaW4g bHV4Lg0KKw0KK1doYXQ6CQkvc3lzL2J1cy9paW8vZGV2aWNlcy9kZXZpY2Vbbl0vaWxsdW1pbmFu Y2UwX3RocmVzaF9mYWxsaW5nX3ZhbHVlDQorS2VybmVsVmVyc2lvbjoJMy4zLXJjMQ0KK0NvbnRh Y3Q6CWxpbnV4LWlpb0B2Z2VyLmtlcm5lbC5vcmcNCitEZXNjcmlwdGlvbjoNCisJCUxvdyAoZmFs bGluZykgdHJpZ2dlciBwb2ludCBmb3IgdGhlIGludGVybmFsIEFMUyBjb21wYXJpc29uDQorCQlm dW5jdGlvbiBmb3IgaW50ZXJydXB0IGdlbmVyYXRpb24uDQorDQorV2hhdDoJCS9zeXMvYnVzL2lp by9kZXZpY2VzL2RldmljZVtuXS9pbGx1bWluYW5jZTBfdGhyZXNoX3Jpc2luZ192YWx1ZQ0KK0tl cm5lbFZlcnNpb246CTMuMy1yYzENCitDb250YWN0OglsaW51eC1paW9Admdlci5rZXJuZWwub3Jn DQorRGVzY3JpcHRpb246DQorCQloaWdoIChyaXNpbmcpIHRyaWdnZXIgcG9pbnQgZm9yIHRoZSBp bnRlcm5hbCBBTFMgY29tcGFyaXNvbg0KKwkJZnVuY3Rpb24gZm9yIGludGVycnVwdCBnZW5lcmF0 aW9uLg0KKw0KK1doYXQ6CQkvc3lzL2J1cy9paW8vZGV2aWNlcy9kZXZpY2Vbbl0vaWxsdW1pbmFu Y2UwX2JvdGhfcmF3DQorS2VybmVsVmVyc2lvbjoJMy4zLXJjMQ0KK0NvbnRhY3Q6CWxpbnV4LWlp b0B2Z2VyLmtlcm5lbC5vcmcNCitEZXNjcmlwdGlvbjoNCisJCVNpbXVsdGFpbmlvdXMgQUxTIGNo YW5uZWwgMSBhbmQgY2hhbm5lbCAyIGRhdGEgcmVwcmVzZW50ZWQgYXMNCisJCWEgMzIgYml0IGlu dGVnZXIuDQorDQorV2hhdDoJCS9zeXMvYnVzL2lpby9kZXZpY2VzL2RldmljZVtuXS9wcm94aW1p dHlfY2FsaWJyYXRlDQorS2VybmVsVmVyc2lvbjoJMy4zLXJjMQ0KK0NvbnRhY3Q6CWxpbnV4LWlp b0B2Z2VyLmtlcm5lbC5vcmcNCitEZXNjcmlwdGlvbjoNCisJCUNhdXNlcyBhbiByZWNhbGN1bGF0 aW9uIGFuZCBhZGp1c3RtZW50IHRvIHRoZQ0KKwkJcHJveGltaXR5X3RocmVzaF9yaXNpbmdfdmFs dWUuDQorDQorV2hhdDoJCS9zeXMvYnVzL2lpby9kZXZpY2VzL2RldmljZVtuXS9wcm94aW1pdHlf dGhyZXNoX2ZhbGxpbmdfdmFsdWUNCitLZXJuZWxWZXJzaW9uOgkzLjMtcmMxDQorQ29udGFjdDoJ bGludXgtaWlvQHZnZXIua2VybmVsLm9yZw0KK0Rlc2NyaXB0aW9uOg0KKwkJTG93IChmYWxsaW5n KSB0cmlnZ2VyIHBvaW50IGZvciB0aGUgaW50ZXJuYWwgcHJveGltaXR5IGNvbXBhcmlzb24NCisJ CWZ1bmN0aW9uIGZvciBpbnRlcnJ1cHQgZ2VuZXJhdGlvbi4NCisNCitXaGF0OgkJL3N5cy9idXMv aWlvL2RldmljZXMvZGV2aWNlW25dL3Byb3hpbWl0eV90aHJlc2hfcmlzaW5nX3ZhbHVlDQorS2Vy bmVsVmVyc2lvbjoJMy4zLXJjMQ0KK0NvbnRhY3Q6CWxpbnV4LWlpb0B2Z2VyLmtlcm5lbC5vcmcN CitEZXNjcmlwdGlvbjoNCisJCWhpZ2ggKHJpc2luZykgdHJpZ2dlciBwb2ludCBmb3IgdGhlIGlu dGVybmFsIHByb3hpbWl0eSBjb21wYXJpc29uDQorCQlmdW5jdGlvbiBmb3IgaW50ZXJydXB0IGdl bmVyYXRpb24uDQorDQorV2hhdDoJCS9zeXMvYnVzL2lpby9kZXZpY2VzL2RldmljZVtuXS9wcm94 aW1pdHlfY2FsaWJzY2FsZQ0KK0tlcm5lbFZlcnNpb246CTMuMy1yYzENCitDb250YWN0OglsaW51 eC1paW9Admdlci5rZXJuZWwub3JnDQorRGVzY3JpcHRpb246DQorCQlIYXJkd2FyZSBvciBzb2Z0 d2FyZSBhcHBsaWVkIGNhbGlicmF0aW9uIHNjYWxlIGZhY3RvciBhc3N1bWVkDQorCQl0byBhY2Nv dW50IGZvciBhdHRlbnVhdGlvbiBkdWUgdG8gaW5kdXN0cmlhbCBkZXNpZ24gKGdsYXNzDQorCQlm aWx0ZXJzIG9yIGFwZXJ0dXJlIGhvbGVzKS4NCisNCitXaGF0OgkJL3N5cy9idXMvaWlvL2Rldmlj ZXMvZGV2aWNlW25dL3Byb3hpbWl0eV9yYXcNCitLZXJuZWxWZXJzaW9uOgkzLjMtcmMxDQorQ29u dGFjdDoJbGludXgtaWlvQHZnZXIua2VybmVsLm9yZw0KK0Rlc2NyaXB0aW9uOg0KKwkJU3RhdGUg b2YgcHJveGltaXR5IGRldGVjdGlvbiBiYXNlZCBvbiB0aGUNCisJCXByb3hpbWl0eV90aHJlc2hf cmlzaW5nX3ZhbHVlLg0KKw0KZGlmZiAtLWdpdCBhL2RyaXZlcnMvc3RhZ2luZy9paW8vbGlnaHQv S2NvbmZpZyBiL2RyaXZlcnMvc3RhZ2luZy9paW8vbGlnaHQvS2NvbmZpZw0KaW5kZXggZTdlOTE1 OS4uMjlkZTMzMyAxMDA2NDQNCi0tLSBhL2RyaXZlcnMvc3RhZ2luZy9paW8vbGlnaHQvS2NvbmZp Zw0KKysrIGIvZHJpdmVycy9zdGFnaW5nL2lpby9saWdodC9LY29uZmlnDQpAQCAtMzEsNCArMzEs MTUgQEAgY29uZmlnIFRTTDI1ODMNCiAJIFByb3ZpZGVzIHN1cHBvcnQgZm9yIHRoZSBUQU9TIHRz bDI1ODAsIHRzbDI1ODEgYW5kIHRzbDI1ODMgZGV2aWNlcy4NCiAJIEFjY2VzcyBBTFMgZGF0YSB2 aWEgaWlvLCBzeXNmcy4NCg0KKwkgVGhpcyBkcml2ZXIgY2FuIGFsc28gYmUgYnVpbHQgYXMgYSBt b2R1bGUuICBJZiBzbywgdGhlIG1vZHVsZQ0KKwkgd2lsbCBiZSBjYWxsZWQgdHNsMjU4My4NCisN Citjb25maWcgVFNMMng3eA0KKwl0cmlzdGF0ZSAiVEFPUyBUU0wvVE1EMng3MSBhbmQgVFNML1RN RDJ4NzIgRmFtaWx5IG9mIGxpZ2h0IGFuZCBwcm94aW1pdHkgc2Vuc29ycyINCisJZGVwZW5kcyBv biBJMkMNCisJaGVscA0KKwkgU3VwcG9ydCBmb3I6IHRzbDI1NzEsIHRzbDI2NzEsIHRtZDI2NzEs IHRzbDI3NzEsIHRtZDI3NzEsIHRzbDI1NzIsIHRzbDI2NzIsDQorCSB0bWQyNjcyLCB0c2wyNzcy LCB0bWQyNzcyIGRldmljZXMuDQorCSBQcm92aWRlcyBpaW9fZXZlbnRzIGFuZCBkaXJlY3QgYWNj ZXNzIHZpYSBzeXNmcy4NCisNCiBlbmRtZW51DQpkaWZmIC0tZ2l0IGEvZHJpdmVycy9zdGFnaW5n L2lpby9saWdodC9NYWtlZmlsZSBiL2RyaXZlcnMvc3RhZ2luZy9paW8vbGlnaHQvTWFrZWZpbGUN CmluZGV4IDMwMTFmYmYuLmZmMTJjNGIgMTAwNjQ0DQotLS0gYS9kcml2ZXJzL3N0YWdpbmcvaWlv L2xpZ2h0L01ha2VmaWxlDQorKysgYi9kcml2ZXJzL3N0YWdpbmcvaWlvL2xpZ2h0L01ha2VmaWxl DQpAQCAtNSwzICs1LDQgQEANCiBvYmotJChDT05GSUdfU0VOU09SU19UU0wyNTYzKQkrPSB0c2wy NTYzLm8NCiBvYmotJChDT05GSUdfU0VOU09SU19JU0wyOTAxOCkJKz0gaXNsMjkwMTgubw0KIG9i ai0kKENPTkZJR19UU0wyNTgzKQkrPSB0c2wyNTgzLm8NCitvYmotJChDT05GSUdfVFNMMng3eCkJ Kz0gdHNsMng3eF9jb3JlLm8NCmRpZmYgLS1naXQgYS9kcml2ZXJzL3N0YWdpbmcvaWlvL2xpZ2h0 L3RzbDJ4N3hfY29yZS5jIGIvZHJpdmVycy9zdGFnaW5nL2lpby9saWdodC90c2wyeDd4X2NvcmUu Yw0KbmV3IGZpbGUgbW9kZSAxMDA2NDQNCmluZGV4IDAwMDAwMDAuLjY3MWY0NzYNCi0tLSAvZGV2 L251bGwNCisrKyBiL2RyaXZlcnMvc3RhZ2luZy9paW8vbGlnaHQvdHNsMng3eF9jb3JlLmMNCkBA IC0wLDAgKzEsMjA1MyBAQA0KKy8qDQorICogRGV2aWNlIGRyaXZlciBmb3IgbW9uaXRvcmluZyBh bWJpZW50IGxpZ2h0IGludGVuc2l0eSBpbiAobHV4KQ0KKyAqIGFuZCBwcm94aW1pdHkgZGV0ZWN0 aW9uIChwcm94KSB3aXRoaW4gdGhlIFRBT1MgVFNMMlg3WCBmYW1pbHkgb2YgZGV2aWNlcy4NCisg Kg0KKyAqIENvcHlyaWdodCAoYykgMjAxMiwgVEFPUyBDb3Jwb3JhdGlvbi4NCisgKg0KKyAqIFRo aXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQv b3IgbW9kaWZ5DQorICogaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJs aWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkNCisgKiB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0 aW9uOyBlaXRoZXIgdmVyc2lvbiAyIG9mIHRoZSBMaWNlbnNlLCBvcg0KKyAqIChhdCB5b3VyIG9w dGlvbikgYW55IGxhdGVyIHZlcnNpb24uDQorICoNCisgKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJp YnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0IFdJVEhPVVQNCisg KiBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZiBNRVJD SEFOVEFCSUxJVFkgb3INCisgKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNl ZSB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yDQorICogbW9yZSBkZXRhaWxzLg0K KyAqDQorICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVy YWwgUHVibGljIExpY2Vuc2UgYWxvbmcNCisgKiB3aXRoIHRoaXMgcHJvZ3JhbTsgaWYgbm90LCB3 cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBJbmMuLA0KKyAqIDUxIEZyYW5r bGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgICAgICAgIDAyMTEwLTEzMDEsIFVT QS4NCisgKi8NCisNCisjaW5jbHVkZSA8bGludXgva2VybmVsLmg+DQorI2luY2x1ZGUgPGxpbnV4 L2kyYy5oPg0KKyNpbmNsdWRlIDxsaW51eC9lcnJuby5oPg0KKyNpbmNsdWRlIDxsaW51eC9kZWxh eS5oPg0KKyNpbmNsdWRlIDxsaW51eC9zdHJpbmcuaD4NCisjaW5jbHVkZSA8bGludXgvbXV0ZXgu aD4NCisjaW5jbHVkZSA8bGludXgvdW5pc3RkLmg+DQorI2luY2x1ZGUgPGxpbnV4L2ludGVycnVw dC5oPg0KKyNpbmNsdWRlIDxsaW51eC9wbGF0Zm9ybV9kZXZpY2UuaD4NCisjaW5jbHVkZSA8bGlu dXgvaW5wdXQuaD4NCisjaW5jbHVkZSA8bGludXgvc2xhYi5oPg0KKyNpbmNsdWRlIDxsaW51eC9w bS5oPg0KKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4NCisjaW5jbHVkZSA8bGludXgvdmVyc2lv bi5oPg0KKw0KKyNpbmNsdWRlIDxsaW51eC9jZGV2Lmg+DQorI2luY2x1ZGUgPGxpbnV4L3N0YXQu aD4NCisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+DQorI2luY2x1ZGUgInRzbDJ4N3hfY29yZS5o Ig0KKyNpbmNsdWRlICIuLi9ldmVudHMuaCINCisjaW5jbHVkZSAiLi4vYnVmZmVyLmgiDQorI2lu Y2x1ZGUgIi4uL2lpby5oIg0KKyNpbmNsdWRlICIuLi9zeXNmcy5oIg0KKw0KKy8qIENhbCBkZWZz Ki8NCisjZGVmaW5lIFBST1hfU1RBVF9DQUwgICAgICAgIDANCisjZGVmaW5lIFBST1hfU1RBVF9T QU1QICAgICAgIDENCisjZGVmaW5lIE1BWF9TQU1QTEVTX0NBTCAgICAgIDIwMA0KKw0KKy8qIFRT TDJYN1ggRGV2aWNlIElEICovDQorI2RlZmluZSBUUklUT05fSUQgICAgMHgwMA0KKyNkZWZpbmUg U1dPUkRGSVNIX0lEIDB4MzANCisjZGVmaW5lIEhBTElCVVRfSUQgICAweDIwDQorDQorLyogTHV4 IGNhbGN1bGF0aW9uIGNvbnN0YW50cyAqLw0KKyNkZWZpbmUgVFNMMlg3WF9MVVhfQ0FMQ19PVkVS X0ZMT1cgICAgICAgIDY1NTM1DQorDQorLyogVEFPUyB0eHgyeDd4IERldmljZSBmYW1pbHkgbWVt YmVycyAqLw0KK2VudW0gew0KKwl0c2wyNTcxLA0KKwl0c2wyNjcxLA0KKwl0bWQyNjcxLA0KKwl0 c2wyNzcxLA0KKwl0bWQyNzcxLA0KKwl0c2wyNTcyLA0KKwl0c2wyNjcyLA0KKwl0bWQyNjcyLA0K Kwl0c2wyNzcyLA0KKwl0bWQyNzcyDQorfTsNCisNCitlbnVtIHsNCisJVFNMMlg3WF9DSElQX1VO S05PV04gPSAwLA0KKwlUU0wyWDdYX0NISVBfV09SS0lORyA9IDEsDQorCVRTTDJYN1hfQ0hJUF9T VVNQRU5ERUQgPSAyDQorfTsNCisNCisvKiBQZXItZGV2aWNlIGRhdGEgKi8NCitzdHJ1Y3QgdHNs Mng3eF9hbHNfaW5mbyB7DQorCXUxNiBhbHNfY2gwOw0KKwl1MTYgYWxzX2NoMTsNCisJdTE2IGx1 eDsNCit9Ow0KKw0KKy8qIHByb3hpbWl0eSBkYXRhICovDQorc3RydWN0IHRzbDJ4N3hfcHJveF9p bmZvIHsNCisJdTE2IHByb3hfZGF0YTsNCisJaW50IHByb3hfZXZlbnQ7DQorfTsNCisNCitzdHJ1 Y3QgcHJveF9zdGF0IHsNCisJdTE2IG1pbjsNCisJdTE2IG1heDsNCisJdTE2IG1lYW47DQorCXVu c2lnbmVkIGxvbmcgc3RkZGV2Ow0KK307DQorDQorc3RydWN0IHRzbDJ4N3hfc2V0dGluZ3Mgew0K KwlpbnQgYWxzX3RpbWU7DQorCWludCBhbHNfZ2FpbjsNCisJaW50IGFsc19nYWluX3RyaW07DQor CWludCB3YWl0X3RpbWU7DQorCWludCBwcnhfdGltZTsNCisJaW50IHByb3hfZ2FpbjsNCisJaW50 IHByb3hfY29uZmlnOw0KKwlpbnQgYWxzX2NhbF90YXJnZXQ7DQorCXU4ICBpbnRlcnJ1cHRzX2Vu Ow0KKwl1OCAgYWxzX3BlcnNpc3RlbmNlOw0KKwlpbnQgYWxzX3RocmVzaF9sb3c7DQorCWludCBh bHNfdGhyZXNoX2hpZ2g7DQorCWludCBwcm94X3RocmVzX2xvdzsNCisJaW50IHByb3hfdGhyZXNf aGlnaDsNCisJaW50IHByb3hfcHVsc2VfY291bnQ7DQorCWludCBwcm94X21heF9zYW1wbGVzX2Nh bDsvKiBmb3IgY2FsaWJyYXRpb24gbW9kZSovDQorDQorfTsNCisNCitzdHJ1Y3QgdHNsMlg3WF9j aGlwX2luZm8gew0KKwlzdHJ1Y3QgaWlvX2NoYW5fc3BlYwljaGFubmVsWzBdOw0KKwljb25zdCBz dHJ1Y3QgaWlvX2luZm8JKmluZm87DQorfTsNCisNCitzdHJ1Y3QgdHNsMlg3WF9jaGlwIHsNCisJ a2VybmVsX3Vsb25nX3QgaWQ7DQorCXN0cnVjdCBtdXRleCBwcm94X211dGV4Ow0KKwlzdHJ1Y3Qg bXV0ZXggYWxzX211dGV4Ow0KKwlzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50Ow0KKwlzdHJ1Y3Qg aWlvX2RldiAqaWlvX2RldjsNCisJc3RydWN0IHRzbDJ4N3hfcHJveF9pbmZvIHByb3hfY3VyX2lu Zm87DQorCXN0cnVjdCB0c2wyeDd4X2Fsc19pbmZvIGFsc19jdXJfaW5mbzsNCisJc3RydWN0IHRz bDJ4N3hfc2V0dGluZ3MgdHNsMng3eF9zZXR0aW5nczsNCisJc3RydWN0IHRzbDJYN1hfcGxhdGZv cm1fZGF0YSAqcGRhdGE7DQorCWludCBhbHNfdGltZV9zY2FsZTsNCisJaW50IGFsc19zYXR1cmF0 aW9uOw0KKwlpbnQgdHNsMng3eF9jaGlwX3N0YXR1czsNCisJdTggdHNsMng3eF9jb25maWdbVFNM Mlg3WF9SRUdfTUFYXTsNCisJYm9vbCBpbml0X2RvbmU7DQorCXN0cnVjdCB3b3JrX3N0cnVjdCB3 b3JrX3RocmVzaDsNCisJczY0IGV2ZW50X3RpbWVzdGFtcDsNCisJLyogVGhpcyBzdHJ1Y3R1cmUg aXMgaW50ZW50aW9uYWxseSBsYXJnZSB0byBhY2NvbW1vZGF0ZQ0KKwkgKiB1cGRhdGVzIHZpYSBz eXNmcy4gKi8NCisJLyogU2l6ZWQgdG8gOSA9IG1heCA4IHNlZ21lbnRzICsgMSB0ZXJtaW5hdGlv biBzZWdtZW50ICovDQorCS8qIEFzc3VtcHRpb24gaXMgb25lIGFuZCBvbmx5IG9uZSB0eXBlIG9m IGdsYXNzIHVzZWQgICovDQorCXN0cnVjdCB0c2wyeDd4X2x1eCB0c2wyeDd4X2RldmljZV9sdXhb TUFYX1RBQkxFX1NJWkVdOw0KK307DQorDQorLyogRGlmZmVyZW50IGRldmljZXMgcmVxdWlyZSBk aWZmZXJlbnQgY29lZmZpY2VudHMgKi8NCitzdGF0aWMgY29uc3Qgc3RydWN0IHRzbDJ4N3hfbHV4 IHRzbDJ4NzFfbHV4X3RhYmxlW10gPSB7DQorCXsgMTQ0NjEsICAgNjExLCAgIDEyMTEgfSwNCisJ eyAxODU0MCwgICAzNTIsICAgIDYyMyB9LA0KKwl7ICAgICAwLCAgICAgMCwgICAgICAwIH0sDQor fTsNCisNCitzdGF0aWMgY29uc3Qgc3RydWN0IHRzbDJ4N3hfbHV4IHRtZDJ4NzFfbHV4X3RhYmxl W10gPSB7DQorCXsgMTE2MzUsICAgMTE1LCAgICAyNTYgfSwNCisJeyAxNTUzNiwgICAgODcsICAg IDE3OSB9LA0KKwl7ICAgICAwLCAgICAgMCwgICAgICAwIH0sDQorfTsNCisNCitzdGF0aWMgY29u c3Qgc3RydWN0IHRzbDJ4N3hfbHV4IHRzbDJ4NzJfbHV4X3RhYmxlW10gPSB7DQorCXsgMTQwMTMs ICAgNDY2LCAgIDkxNyB9LA0KKwl7IDE4MjIyLCAgIDMxMCwgICA1NTIgfSwNCisJeyAgICAgMCwg ICAgIDAsICAgICAwIH0sDQorfTsNCisNCitzdGF0aWMgY29uc3Qgc3RydWN0IHRzbDJ4N3hfbHV4 IHRtZDJ4NzJfbHV4X3RhYmxlW10gPSB7DQorCXsgMTMyMTgsICAgMTMwLCAgIDI2MiB9LA0KKwl7 IDE3NTkyLCAgIDkyLCAgICAxNjkgfSwNCisJeyAgICAgMCwgICAgIDAsICAgICAwIH0sDQorfTsN CisNCitzdGF0aWMgY29uc3Qgc3RydWN0IHRzbDJ4N3hfbHV4ICp0c2wyeDd4X2RlZmF1bHRfbHV4 X3RhYmxlX2dyb3VwW10gPSB7DQorCVt0c2wyNTcxXSA9IHRzbDJ4NzFfbHV4X3RhYmxlLA0KKwlb dHNsMjY3MV0gPQl0c2wyeDcxX2x1eF90YWJsZSwNCisJW3RtZDI2NzFdID0JdG1kMng3MV9sdXhf dGFibGUsDQorCVt0c2wyNzcxXSA9CXRzbDJ4NzFfbHV4X3RhYmxlLA0KKwlbdG1kMjc3MV0gPQl0 bWQyeDcxX2x1eF90YWJsZSwNCisJW3RzbDI1NzJdID0JdHNsMng3Ml9sdXhfdGFibGUsDQorCVt0 c2wyNjcyXSA9CXRzbDJ4NzJfbHV4X3RhYmxlLA0KKwlbdG1kMjY3Ml0gPSB0bWQyeDcyX2x1eF90 YWJsZSwNCisJW3RzbDI3NzJdID0JdHNsMng3Ml9sdXhfdGFibGUsDQorCVt0bWQyNzcyXSA9CXRt ZDJ4NzJfbHV4X3RhYmxlLA0KK307DQorDQorc3RydWN0IGFsc19nYWluYWRqIHsNCisJczE2IGNo MDsNCisJczE2IGNoMTsNCit9Ow0KKw0KKy8qIFVzZWQgdG8gdmFsaWRhdGUgdGhlIEFMUyBnYWlu IHNlbGVjdGlvbiBpbmRleCAqLw0KK3N0YXRpYyBjb25zdCBzdHJ1Y3QgYWxzX2dhaW5hZGogdHNs Mlg3WF9hbHNfZ2FpbmFkaltdID0gew0KKwl7IDEsIDEgfSwNCisJeyA4LCA4IH0sDQorCXsgMTYs IDE2IH0sDQorCXsgMTIwLCAxMjAgfQ0KK307DQorDQorDQorLyogTm90IHVzaW5nIGNoYW5uZWxz ICovDQorc3RhdGljIGNvbnN0IHN0cnVjdCBpaW9fY2hhbl9zcGVjIHRzbDJYN1hfY2hhbm5lbHNb XSA9IHt9Ow0KKw0KKy8qDQorICogUmVhZCBhIG51bWJlciBvZiBieXRlcyBzdGFydGluZyBhdCBy ZWdpc3RlciAocmVnKSBsb2NhdGlvbi4NCisgKiBSZXR1cm4gMCwgb3IgaTJjX3NtYnVzX3dyaXRl X2J5dGUgRVJST1IgY29kZS4NCisgKi8NCitzdGF0aWMgaW50DQordHNsMng3eF9pMmNfcmVhZChz dHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LCB1OCByZWcsIHU4ICp2YWwsIHVuc2lnbmVkIGludCBs ZW4pDQorew0KKwlpbnQgcmV0Ow0KKwlpbnQgaTsNCisNCisJZm9yIChpID0gMDsgaSA8IGxlbjsg aSsrKSB7DQorCQkvKiBzZWxlY3QgcmVnaXN0ZXIgdG8gd3JpdGUgKi8NCisJCXJldCA9IGkyY19z bWJ1c193cml0ZV9ieXRlKGNsaWVudCwgKFRTTDJYN1hfQ01EX1JFRyB8IHJlZykpOw0KKwkJaWYg KHJldCA8IDApIHsNCisJCQlkZXZfZXJyKCZjbGllbnQtPmRldiwgInRzbDJ4N3hfaTJjX3JlYWQg ZmFpbGVkIHRvIHdyaXRlIg0KKwkJCQkiIHJlZ2lzdGVyICV4XG4iLCByZWcpOw0KKwkJCXJldHVy biByZXQ7DQorCQl9DQorCQkvKiByZWFkIHRoZSBkYXRhICovDQorCQkqdmFsID0gaTJjX3NtYnVz X3JlYWRfYnl0ZShjbGllbnQpOw0KKwkJdmFsKys7DQorCQlyZWcrKzsNCisJfQ0KKwlyZXR1cm4g MDsNCit9DQorDQorLyoNCisgKiBSZWFkcyBhbmQgY2FsY3VsYXRlcyBjdXJyZW50IGx1eCB2YWx1 ZS4NCisgKiBUaGUgcmF3IGNoMCBhbmQgY2gxIHZhbHVlcyBvZiB0aGUgYW1iaWVudCBsaWdodCBz ZW5zZWQgaW4gdGhlIGxhc3QNCisgKiBpbnRlZ3JhdGlvbiBjeWNsZSBhcmUgcmVhZCBmcm9tIHRo ZSBkZXZpY2UuDQorICogVGltZSBzY2FsZSBmYWN0b3IgYXJyYXkgdmFsdWVzIGFyZSBhZGp1c3Rl ZCBiYXNlZCBvbiB0aGUgaW50ZWdyYXRpb24gdGltZS4NCisgKiBUaGUgcmF3IHZhbHVlcyBhcmUg bXVsdGlwbGllZCBieSBhIHNjYWxlIGZhY3RvciwgYW5kIGRldmljZSBnYWluIGlzIG9idGFpbmVk DQorICogdXNpbmcgZ2FpbiBpbmRleC4gTGltaXQgY2hlY2tzIGFyZSBkb25lIG5leHQsIHRoZW4g dGhlIHJhdGlvIG9mIGEgbXVsdGlwbGUNCisgKiBvZiBjaDEgdmFsdWUsIHRvIHRoZSBjaDAgdmFs dWUsIGlzIGNhbGN1bGF0ZWQuIFRoZSBhcnJheSB0c2wyeDd4X2RldmljZV9sdXhbXQ0KKyAqIGRl Y2xhcmVkIGFib3ZlIGlzIHRoZW4gc2Nhbm5lZCB0byBmaW5kIHRoZSBmaXJzdCByYXRpbyB2YWx1 ZSB0aGF0IGlzIGp1c3QNCisgKiBhYm92ZSB0aGUgcmF0aW8gd2UganVzdCBjYWxjdWxhdGVkLiBU aGUgY2gwIGFuZCBjaDEgbXVsdGlwbGllciBjb25zdGFudHMgaW4NCisgKiB0aGUgYXJyYXkgYXJl IHRoZW4gdXNlZCBhbG9uZyB3aXRoIHRoZSB0aW1lIHNjYWxlIGZhY3RvciBhcnJheSB2YWx1ZXMs IHRvDQorICogY2FsY3VsYXRlIHRoZSBsdXguDQorICovDQorc3RhdGljIGludCB0c2wyeDd4X2dl dF9sdXgoc3RydWN0IGlpb19kZXYgKmluZGlvX2RldikNCit7DQorCXUxNiBjaDAsIGNoMTsgLyog c2VwYXJhdGVkIGNoMC9jaDEgZGF0YSBmcm9tIGRldmljZSAqLw0KKwl1MzIgbHV4OyAvKiByYXcg bHV4IGNhbGN1bGF0ZWQgZnJvbSBkZXZpY2UgZGF0YSAqLw0KKwl1NjQgbHV4NjQ7DQorCXUzMiBy YXRpbzsNCisjcHJhZ21hIHBhY2soNCkNCisJdTggYnVmWzRdOw0KKwlzdHJ1Y3QgdHNsMng3eF9s dXggKnA7DQorCXN0cnVjdCB0c2wyWDdYX2NoaXAgKmNoaXAgPSBpaW9fcHJpdihpbmRpb19kZXYp Ow0KKwlpbnQgaSwgcmV0Ow0KKwl1MzIgY2gwbHV4ID0gMDsNCisJdTMyIGNoMWx1eCA9IDA7DQor DQorCWlmIChtdXRleF90cnlsb2NrKCZjaGlwLT5hbHNfbXV0ZXgpID09IDApIHsNCisJCWRldl9p bmZvKCZjaGlwLT5jbGllbnQtPmRldiwgInRzbDJ4N3hfZ2V0X2x1eCBkZXZpY2UgaXMgYnVzeVxu Iik7DQorCQlyZXR1cm4gY2hpcC0+YWxzX2N1cl9pbmZvLmx1eDsgLyogYnVzeSwgc28gcmV0dXJu IExBU1QgVkFMVUUgKi8NCisJfQ0KKw0KKwlpZiAoY2hpcC0+dHNsMng3eF9jaGlwX3N0YXR1cyAh PSBUU0wyWDdYX0NISVBfV09SS0lORykgew0KKwkJLyogZGV2aWNlIGlzIG5vdCBlbmFibGVkICov DQorCQlkZXZfZXJyKCZjaGlwLT5jbGllbnQtPmRldiwgInRzbDJ4N3hfZ2V0X2x1eCBkZXZpY2Ug aXMgbm90IGVuYWJsZWRcbiIpOw0KKwkJcmV0ID0gLUVCVVNZIDsNCisJCWdvdG8gb3V0X3VubG9j azsNCisJfQ0KKw0KKwlyZXQgPSB0c2wyeDd4X2kyY19yZWFkKGNoaXAtPmNsaWVudCwNCisJCShU U0wyWDdYX0NNRF9SRUcgfCBUU0wyWDdYX1NUQVRVUyksICZidWZbMF0sIDEpOw0KKwlpZiAocmV0 IDwgMCkgew0KKwkJZGV2X2VycigmY2hpcC0+Y2xpZW50LT5kZXYsDQorCQkJInRzbDJ4N3hfZ2V0 X2x1eCBmYWlsZWQgdG8gcmVhZCBDTURfUkVHXG4iKTsNCisJCWdvdG8gb3V0X3VubG9jazsNCisJ fQ0KKwkvKiBpcyBkYXRhIG5ldyAmIHZhbGlkICovDQorCWlmICghKGJ1ZlswXSAmIFRTTDJYN1hf U1RBX0FEQ19WQUxJRCkpIHsNCisJCWRldl9lcnIoJmNoaXAtPmNsaWVudC0+ZGV2LA0KKwkJCSJ0 c2wyeDd4X2dldF9sdXggZGF0YSBub3QgdmFsaWQgeWV0XG4iKTsNCisJCXJldCA9IGNoaXAtPmFs c19jdXJfaW5mby5sdXg7IC8qIHJldHVybiBMQVNUIFZBTFVFICovDQorCQlnb3RvIG91dF91bmxv Y2s7DQorCX0NCisNCisJZm9yIChpID0gMDsgaSA8IDQ7IGkrKykgew0KKwkJcmV0ID0gdHNsMng3 eF9pMmNfcmVhZChjaGlwLT5jbGllbnQsDQorCQkJKFRTTDJYN1hfQ01EX1JFRyB8IChUU0wyWDdY X0FMU19DSEFOMExPICsgaSkpLA0KKwkJCSZidWZbaV0sIDEpOw0KKwkJaWYgKHJldCA8IDApIHsN CisJCQlkZXZfZXJyKCZjaGlwLT5jbGllbnQtPmRldiwNCisJCQkJInRzbDJ4N3hfZ2V0X2x1eCBm YWlsZWQgdG8gcmVhZCINCisJCQkJIiByZXQ6ICV4XG4iLCByZXQpOw0KKwkJCWdvdG8gb3V0X3Vu bG9jazsNCisJCX0NCisJfQ0KKw0KKwkvKiBjbGVhciBzdGF0dXMsIHJlYWxseSBpbnRlcnJ1cHQg c3RhdHVzICggYXJlIG9mZiksDQorCWJ1dCB3ZSB1c2UgdGhlIGJpdCBhbnl3YXkgKi8NCisJcmV0 ID0gaTJjX3NtYnVzX3dyaXRlX2J5dGUoY2hpcC0+Y2xpZW50LA0KKwkJKFRTTDJYN1hfQ01EX1JF RyB8DQorCQkJCVRTTDJYN1hfQ01EX1NQTF9GTiB8DQorCQkJCVRTTDJYN1hfQ01EX0FMU19JTlRf Q0xSKSk7DQorDQorCWlmIChyZXQgPCAwKSB7DQorCQlkZXZfZXJyKCZjaGlwLT5jbGllbnQtPmRl diwNCisJCSJ0c2wyeDd4X2kyY193cml0ZV9jb21tYW5kIGZhaWxlZCBpbiB0c2wyeDd4X2dldF9s dXgsIGVyciA9ICVkXG4iLA0KKwkJCXJldCk7DQorCQlnb3RvIG91dF91bmxvY2s7IC8qIGhhdmUg bm8gZGF0YSwgc28gcmV0dXJuIGZhaWx1cmUgKi8NCisJfQ0KKw0KKwkvKiBleHRyYWN0IEFMUy9s dXggZGF0YSAqLw0KKwljaDAgPSBsZTE2X3RvX2NwdXAoKGNvbnN0IF9fbGUxNiAqKSZidWZbMF0p Ow0KKwljaDEgPSBsZTE2X3RvX2NwdXAoKGNvbnN0IF9fbGUxNiAqKSZidWZbMl0pOw0KKw0KKwlj aGlwLT5hbHNfY3VyX2luZm8uYWxzX2NoMCA9IGNoMDsNCisJY2hpcC0+YWxzX2N1cl9pbmZvLmFs c19jaDEgPSBjaDE7DQorDQorCWlmICgoY2gwID49IGNoaXAtPmFsc19zYXR1cmF0aW9uKSB8fCAo Y2gxID49IGNoaXAtPmFsc19zYXR1cmF0aW9uKSkNCisJCWdvdG8gcmV0dXJuX21heDsNCisNCisJ aWYgKGNoMCA9PSAwKSB7DQorCQkvKiBoYXZlIG5vIGRhdGEsIHNvIHJldHVybiBMQVNUIFZBTFVF ICovDQorCQlyZXQgPSBjaGlwLT5hbHNfY3VyX2luZm8ubHV4ID0gMDsNCisJCWdvdG8gb3V0X3Vu bG9jazsNCisJfQ0KKwkvKiBjYWxjdWxhdGUgcmF0aW8gKi8NCisJcmF0aW8gPSAoY2gxIDw8IDE1 KSAvIGNoMDsNCisJLyogY29udmVydCB0byB1bnNjYWxlZCBsdXggdXNpbmcgdGhlIHBvaW50ZXIg dG8gdGhlIHRhYmxlICovDQorCWZvciAocCA9IChzdHJ1Y3QgdHNsMng3eF9sdXggKikgY2hpcC0+ dHNsMng3eF9kZXZpY2VfbHV4Ow0KKwkgICAgIHAtPnJhdGlvICE9IDAgJiYgcC0+cmF0aW8gPCBy YXRpbzsgcCsrKQ0KKwkJOw0KKw0KKwlpZiAocC0+cmF0aW8gPT0gMCkgew0KKwkJbHV4ID0gMDsN CisJfSBlbHNlIHsNCisJCWNoMGx1eCA9ICgoY2gwICogcC0+Y2gwKSArDQorCQkodHNsMlg3WF9h bHNfZ2FpbmFkaltjaGlwLT50c2wyeDd4X3NldHRpbmdzLmFsc19nYWluXS5jaDAgPj4gMSkpDQor CQkvIHRzbDJYN1hfYWxzX2dhaW5hZGpbY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5hbHNfZ2Fpbl0u Y2gwOw0KKw0KKwkJY2gxbHV4ID0gKChjaDEgKiBwLT5jaDEpICsNCisJCSh0c2wyWDdYX2Fsc19n YWluYWRqW2NoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX2dhaW5dLmNoMSA+PiAxKSkNCisJCS8g dHNsMlg3WF9hbHNfZ2FpbmFkaltjaGlwLT50c2wyeDd4X3NldHRpbmdzLmFsc19nYWluXS5jaDE7 DQorDQorCQlsdXggPSBjaDBsdXggLSBjaDFsdXg7DQorCX0NCisNCisJLyogbm90ZTogbHV4IGlz IDMxIGJpdCBtYXggYXQgdGhpcyBwb2ludCAqLw0KKwlpZiAoY2gxbHV4ID4gY2gwbHV4KSB7DQor CQlkZXZfZGJnKCZjaGlwLT5jbGllbnQtPmRldiwgIk5vIERhdGEgLSBSZXR1cm4gbGFzdCB2YWx1 ZVxuIik7DQorCQlyZXQgPSBjaGlwLT5hbHNfY3VyX2luZm8ubHV4ID0gMDsNCisJCWdvdG8gb3V0 X3VubG9jazsNCisJfQ0KKw0KKwkvKiBhZGp1c3QgZm9yIGFjdGl2ZSB0aW1lIHNjYWxlICovDQor CWlmIChjaGlwLT5hbHNfdGltZV9zY2FsZSA9PSAwKQ0KKwkJbHV4ID0gMDsNCisJZWxzZQ0KKwkJ bHV4ID0gKGx1eCArIChjaGlwLT5hbHNfdGltZV9zY2FsZSA+PiAxKSkgLw0KKwkJCWNoaXAtPmFs c190aW1lX3NjYWxlOw0KKw0KKwkvKiBhZGp1c3QgZm9yIGFjdGl2ZSBnYWluIHNjYWxlDQorCSAq IFRoZSB0c2wyeDd4X2RldmljZV9sdXggdGFibGVzIGhhdmUgYSBmYWN0b3Igb2YgMjU2IGJ1aWx0 LWluLg0KKwkgKiBVc2VyLXNwZWNpZmllZCBnYWluIHByb3ZpZGVzIGEgbXVsdGlwbGllci4NCisJ ICogQXBwbHkgdXNlci1zcGVjaWZpZWQgZ2FpbiBiZWZvcmUgc2hpZnRpbmcgcmlnaHQgdG8gcmV0 YWluIHByZWNpc2lvbi4NCisJICogVXNlIDY0IGJpdHMgdG8gYXZvaWQgb3ZlcmZsb3cgb24gbXVs dGlwbGljYXRpb24uDQorCSAqIFRoZW4gZ28gYmFjayB0byAzMiBiaXRzIGJlZm9yZSBkaXZpc2lv biB0byBhdm9pZCB1c2luZyBkaXZfdTY0KCkuDQorCSAqLw0KKwlsdXg2NCA9IGx1eDsNCisJbHV4 NjQgPSBsdXg2NCAqIGNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX2dhaW5fdHJpbTsNCisJbHV4 NjQgPj49IDg7DQorCWx1eCA9IGx1eDY0Ow0KKwlsdXggPSAobHV4ICsgNTAwKSAvIDEwMDA7DQor DQorCWlmIChsdXggPiBUU0wyWDdYX0xVWF9DQUxDX09WRVJfRkxPVykgeyAvKiBjaGVjayBmb3Ig b3ZlcmZsb3cgKi8NCityZXR1cm5fbWF4Og0KKwkJbHV4ID0gVFNMMlg3WF9MVVhfQ0FMQ19PVkVS X0ZMT1c7DQorCX0NCisNCisJLyogVXBkYXRlIHRoZSBzdHJ1Y3R1cmUgd2l0aCB0aGUgbGF0ZXN0 IFZBTElEIGx1eC4gKi8NCisJY2hpcC0+YWxzX2N1cl9pbmZvLmx1eCA9IGx1eDsNCisJcmV0ID0g bHV4Ow0KKw0KK291dF91bmxvY2s6DQorCW11dGV4X3VubG9jaygmY2hpcC0+YWxzX211dGV4KTsN CisJcmV0dXJuIHJldDsNCisNCit9DQorDQorLyoNCisgKiBQcm94aW1pdHkgcG9sbCBmdW5jdGlv biAtIGlmIHZhbGlkIGRhdGEgaXMgYXZhaWxhYmxlLCByZWFkIGFuZCBmb3JtIHRoZSBjaDANCisg KiBhbmQgcHJveCBkYXRhIHZhbHVlcywgY2hlY2sgZm9yIGxpbWl0cyBvbiB0aGUgY2gwIHZhbHVl LCBhbmQgY2hlY2sgdGhlIHByb3gNCisgKiBkYXRhIGFnYWluc3QgdGhlIGN1cnJlbnQgdGhyZXNo b2xkcywgdG8gc2V0IHRoZSBldmVudCBzdGF0dXMgYWNjb3JkaW5nbHkuDQorICovDQorc3RhdGlj IGludCB0c2wyeDd4X3Byb3hfcG9sbChzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2KQ0KK3sNCisj ZGVmaW5lIENPTlNFQ1VUSVZFX1JFVFJJRVMgNTANCisNCisJaW50IGk7DQorCWludCByZXQ7DQor CXU4IHN0YXR1czsNCisJdTggY2hkYXRhWzJdOw0KKwlpbnQgZXJyX2NudDsNCisJc3RydWN0IHRz bDJYN1hfY2hpcCAqY2hpcCA9IGlpb19wcml2KGluZGlvX2Rldik7DQorDQorCWlmIChtdXRleF90 cnlsb2NrKCZjaGlwLT5wcm94X211dGV4KSA9PSAwKSB7DQorCQlkZXZfZXJyKCZjaGlwLT5jbGll bnQtPmRldiwgIkNhbid0IGdldCBwcm94IG11dGV4XG4iKTsNCisJCXJldHVybiAtRUJVU1k7DQor CX0NCisNCisJZXJyX2NudCA9IDA7DQorDQordHJ5X2FnYWluOg0KKwlyZXQgPSB0c2wyeDd4X2ky Y19yZWFkKGNoaXAtPmNsaWVudCwNCisJCShUU0wyWDdYX0NNRF9SRUcgfCBUU0wyWDdYX1NUQVRV UyksICZzdGF0dXMsIDEpOw0KKwlpZiAocmV0IDwgMCkgew0KKwkJZGV2X2VycigmY2hpcC0+Y2xp ZW50LT5kZXYsDQorCQkJIlJlYWQgcmVncyBmYWlsZWQgaW4gdHNsMng3eF9wcm94X3BvbGwoKSAt IEFcbiIpOw0KKwkJbXV0ZXhfdW5sb2NrKCZjaGlwLT5wcm94X211dGV4KTsNCisJCXJldHVybiBy ZXQ7DQorCX0NCisNCisJLypQcm94IGludGVycnVwdCBhc3NlcnRlZCovDQorCWlmICgoKGNoaXAt PnRzbDJ4N3hfc2V0dGluZ3MuaW50ZXJydXB0c19lbiA8PCA0KQ0KKwkJCSYgQ05UTF9QUk9YX0lO VF9FTkJMKSkgew0KKwkJaWYgKCEoc3RhdHVzICYgVFNMMlg3WF9TVEFfQURDX1ZBTElEKSkgew0K KwkJCWVycl9jbnQrKzsNCisJCQlpZiAoZXJyX2NudCA+IENPTlNFQ1VUSVZFX1JFVFJJRVMpIHsN CisJCQkJbXV0ZXhfdW5sb2NrKCZjaGlwLT5wcm94X211dGV4KTsNCisJCQkJZGV2X2VycigmY2hp cC0+Y2xpZW50LT5kZXYsDQorCQkJCSJDb25zZWMuIHJldHJpZXMgZXhjZWVkZWRcbiIpOw0KKwkJ CQlyZXR1cm4gY2hpcC0+cHJveF9jdXJfaW5mby5wcm94X2V2ZW50Ow0KKwkJCX0NCisJCQlnb3Rv IHRyeV9hZ2FpbjsNCisJCX0NCisJfQ0KKw0KKwlmb3IgKGkgPSAwOyBpIDwgMjsgaSsrKSB7DQor CQlyZXQgPSB0c2wyeDd4X2kyY19yZWFkKGNoaXAtPmNsaWVudCwNCisJCQkoVFNMMlg3WF9DTURf UkVHIHwNCisJCQkJCShUU0wyWDdYX1BSWF9MTyArIGkpKSwgJmNoZGF0YVtpXSwgMSk7DQorCQlp ZiAocmV0IDwgMCkgew0KKwkJCWRldl9lcnIoJmNoaXAtPmNsaWVudC0+ZGV2LA0KKwkJCSJSZWFk IHJlZ3MgZmFpbGVkIGluIHRzbDJ4N3hfcHJveF9wb2xsKCkgLSBCXG4iKTsNCisJCQltdXRleF91 bmxvY2soJmNoaXAtPnByb3hfbXV0ZXgpOw0KKwkJCXJldHVybiByZXQ7DQorCQl9DQorCX0NCisN CisJY2hpcC0+cHJveF9jdXJfaW5mby5wcm94X2RhdGEgPSAoY2hkYXRhWzFdPDw4KXxjaGRhdGFb MF07DQorDQorCWlmIChjaGlwLT5wcm94X2N1cl9pbmZvLnByb3hfZGF0YSA+PQ0KKwkJCWNoaXAt PnRzbDJ4N3hfc2V0dGluZ3MucHJveF90aHJlc19oaWdoKQ0KKwkJY2hpcC0+cHJveF9jdXJfaW5m by5wcm94X2V2ZW50ID0gMTsNCisJZWxzZQ0KKwkJY2hpcC0+cHJveF9jdXJfaW5mby5wcm94X2V2 ZW50ID0gMDsNCisNCisJbXV0ZXhfdW5sb2NrKCZjaGlwLT5wcm94X211dGV4KTsNCisJcmV0dXJu IGNoaXAtPnByb3hfY3VyX2luZm8ucHJveF9ldmVudDsNCit9DQorDQorLyoNCisgKiBQcm92aWRl cyBpbml0aWFsIG9wZXJhdGlvbmFsIHBhcmFtZXRlciBkZWZhdWx0cy4NCisgKiBUaGVzZSBkZWZh dWx0cyBtYXkgYmUgY2hhbmdlZCB0aHJvdWdoIHRoZSBkZXZpY2UncyBzeXNmcyBmaWxlcy4NCisg Ki8NCitzdGF0aWMgdm9pZCB0c2wyeDd4X2RlZmF1bHRzKHN0cnVjdCB0c2wyWDdYX2NoaXAgKmNo aXApDQorew0KKwkvKiBPcGVyYXRpb25hbCBwYXJhbWV0ZXJzICovDQorCWNoaXAtPnRzbDJ4N3hf c2V0dGluZ3MuYWxzX3RpbWUgPSAyMDA7DQorCS8qIG11c3QgYmUgYSBtdWx0aXBsZSBvZiA1MG1T ICovDQorCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX2dhaW4gPSAwOw0KKwkvKiB0aGlzIGlz IGFjdHVhbGx5IGFuIGluZGV4IGludG8gdGhlIGdhaW4gdGFibGUgKi8NCisJY2hpcC0+dHNsMng3 eF9zZXR0aW5ncy5wcnhfdGltZSA9IDB4ZmU7IC8qNS40IG1TICovDQorCS8qIDIuN21zIHByb3gg aW50ZWdyYXRpb24gdGltZSAtIGRlY3JlYXNlIHRvIGluY3JlYXNlIHRpbWUgKi8NCisJLyogZGVj cmVhc2VzIGluIDIuNyBtcyBpbnRlcnZhbHMgKi8NCisJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5w cm94X2dhaW4gPSAxOw0KKwkvKiB0aGVzZSBhcmUgYml0cyAzOjIgb2YgcmVnIDB4MGY6IDA9eDEs MT14MiwyPXg0LDM9eDggKi8NCisJLyogYXNzdW1lIGNsZWFyIGdsYXNzIGFzIGRlZmF1bHQgKi8N CisJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy53YWl0X3RpbWUgPSAyNDU7DQorCS8qIFRpbWUgYmV0 d2VlbiBQUlggYW5kIEFMUyBjeWNsZXMgLWRlY3JlYXNlIHRvIGluY3JlYXNlIHRpbWUgKi8NCisJ LyogZGVjcmVhc2VzIGluIDIuNyBtcyBpbnRlcnZhbHMgKi8NCisJY2hpcC0+dHNsMng3eF9zZXR0 aW5ncy5wcm94X2NvbmZpZyA9IDA7DQorCS8qIFByb3ggY29uZmlndXJhdGlvbiBmaWx0ZXJzICov DQorCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX2dhaW5fdHJpbSA9IDEwMDA7DQorCS8qIGRl ZmF1bHQgZ2FpbiB0cmltIHRvIGFjY291bnQgZm9yIGFwZXJ0dXJlIGVmZmVjdHMgKi8NCisJY2hp cC0+dHNsMng3eF9zZXR0aW5ncy5hbHNfY2FsX3RhcmdldCA9IDE1MDsNCisJLyogS25vd24gZXh0 ZXJuYWwgQUxTIHJlYWRpbmcgdXNlZCBmb3IgY2FsaWJyYXRpb24gKi8NCisJY2hpcC0+dHNsMng3 eF9zZXR0aW5ncy5hbHNfdGhyZXNoX2xvdyA9IDIwMDsNCisJLyogQ0gwICdsb3cnIGNvdW50IHRv IHRyaWdnZXIgaW50ZXJydXB0ICovDQorCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX3RocmVz aF9oaWdoID0gMjU2Ow0KKwkvKiBDSDAgJ2hpZ2gnIGNvdW50IHRvIHRyaWdnZXIgaW50ZXJydXB0 ICovDQorCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX3BlcnNpc3RlbmNlID0gMHhGRjsNCisJ LyogTnVtYmVyIG9mICdvdXQgb2YgbGltaXRzJyBBREMgcmVhZGluZ3MgUFJYL0FMUyovDQorCWNo aXAtPnRzbDJ4N3hfc2V0dGluZ3MuaW50ZXJydXB0c19lbiA9IDB4MDA7DQorCS8qIERlZmF1bHQg aW50ZXJydXB0KHMpIGVuYWJsZWQuDQorCSAqIDB4MDAgPSBub25lLCAweDEwID0gYWxzLCAweDIw ID0gcHJ4IDB4MzAgPSBidGggKi8NCisJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5wcm94X3RocmVz X2xvdyAgPSAwOw0KKwljaGlwLT50c2wyeDd4X3NldHRpbmdzLnByb3hfdGhyZXNfaGlnaCA9IDUx MjsNCisJLypkZWZhdWx0IHRocmVzaG9sZCAoYWRqdXN0IGVpdGhlciBtYW51YWxseSBvciB3aXRo IGNhbCByb3V0aW5lKi8NCisJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5wcm94X21heF9zYW1wbGVz X2NhbCA9IDMwOw0KKwljaGlwLT50c2wyeDd4X3NldHRpbmdzLnByb3hfcHVsc2VfY291bnQgPSA4 Ow0KKw0KKwkvKiBMb2FkIHVwIHRoZSBsdXggdGFibGUuIENhbiBiZSBjaGFuZ2VkIGxhdGVyIHZp YSBBQkkgKi8NCisJaWYgKGNoaXAtPnBkYXRhICYmIGNoaXAtPnBkYXRhLT5wbGF0Zm9ybV9sdXhf dGFibGVbMF0ucmF0aW8gIT0gMCkNCisJCW1lbWNweShjaGlwLT50c2wyeDd4X2RldmljZV9sdXgs DQorCQkJY2hpcC0+cGRhdGEtPnBsYXRmb3JtX2x1eF90YWJsZSwNCisJCQlzaXplb2YoY2hpcC0+ cGRhdGEtPnBsYXRmb3JtX2x1eF90YWJsZSkpOw0KKwllbHNlDQorCQltZW1jcHkoY2hpcC0+dHNs Mng3eF9kZXZpY2VfbHV4LA0KKwkJKHN0cnVjdCB0c2wyeDd4X2x1eCAqKXRzbDJ4N3hfZGVmYXVs dF9sdXhfdGFibGVfZ3JvdXBbY2hpcC0+aWRdLA0KKwkJCQlNQVhfREVGQVVMVF9UQUJMRV9CWVRF Uyk7DQorDQorfQ0KKw0KKy8qDQorICogT2J0YWluIHNpbmdsZSByZWFkaW5nIGFuZCBjYWxjdWxh dGUgdGhlIGFsc19nYWluX3RyaW0NCisgKiAobGF0ZXIgdXNlZCB0byBkZXJpdmUgYWN0dWFsIGx1 eCkuDQorICogUmV0dXJuIHVwZGF0ZWQgZ2Fpbl90cmltIHZhbHVlLg0KKyAqLw0KK3N0YXRpYyBp bnQgdHNsMng3eF9hbHNfY2FsaWJyYXRlKHN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYpDQorew0K KwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0gaWlvX3ByaXYoaW5kaW9fZGV2KTsNCisJdTgg cmVnX3ZhbDsNCisJaW50IGdhaW5fdHJpbV92YWw7DQorCWludCByZXQ7DQorCWludCBsdXhfdmFs Ow0KKw0KKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZShjaGlwLT5jbGllbnQsDQorCQkJKFRT TDJYN1hfQ01EX1JFRyB8IFRTTDJYN1hfQ05UUkwpKTsNCisJaWYgKHJldCA8IDApIHsNCisJCWRl dl9lcnIoJmNoaXAtPmNsaWVudC0+ZGV2LA0KKwkJInRzbDJ4N3hfYWxzX2NhbGlicmF0ZSBmYWls ZWQgdG8gd3JpdGUgQ05UUkwgcmVnaXN0ZXIsIHJldD0lZFxuIiwNCisJCQlyZXQpOw0KKwkJcmV0 dXJuIHJldDsNCisJfQ0KKw0KKwlyZWdfdmFsID0gaTJjX3NtYnVzX3JlYWRfYnl0ZShjaGlwLT5j bGllbnQpOw0KKwlpZiAoKHJlZ192YWwgJiAoVFNMMlg3WF9DTlRMX0FEQ19FTkJMIHwgVFNMMlg3 WF9DTlRMX1BXUl9PTikpDQorCQkJIT0gKFRTTDJYN1hfQ05UTF9BRENfRU5CTCB8IFRTTDJYN1hf Q05UTF9QV1JfT04pKSB7DQorCQlkZXZfZXJyKCZjaGlwLT5jbGllbnQtPmRldiwNCisJCQkidHNs Mng3eF9hbHNfY2FsaWJyYXRlIGZhaWxlZDogQURDIG5vdCBlbmFibGVkXG4iKTsNCisJCXJldHVy biAtMTsNCisJfQ0KKw0KKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZShjaGlwLT5jbGllbnQs DQorCQkJKFRTTDJYN1hfQ01EX1JFRyB8IFRTTDJYN1hfQ05UUkwpKTsNCisJaWYgKHJldCA8IDAp IHsNCisJCWRldl9lcnIoJmNoaXAtPmNsaWVudC0+ZGV2LA0KKwkJInRzbDJ4N3hfYWxzX2NhbGli cmF0ZSBmYWlsZWQgdG8gd3JpdGUgY3RybCByZWc6IHJldD0lZFxuIiwNCisJCQlyZXQpOw0KKwkJ cmV0dXJuIHJldDsNCisJfQ0KKwlyZWdfdmFsID0gaTJjX3NtYnVzX3JlYWRfYnl0ZShjaGlwLT5j bGllbnQpOw0KKw0KKwlpZiAoKHJlZ192YWwgJiBUU0wyWDdYX1NUQV9BRENfVkFMSUQpICE9IFRT TDJYN1hfU1RBX0FEQ19WQUxJRCkgew0KKwkJZGV2X2VycigmY2hpcC0+Y2xpZW50LT5kZXYsDQor CQkidHNsMng3eF9hbHNfY2FsaWJyYXRlIGZhaWxlZDogU1RBVFVTIC0gQURDIG5vdCB2YWxpZC5c biIpOw0KKwkJcmV0dXJuIC1FTk9EQVRBOw0KKwl9DQorCWx1eF92YWwgPSB0c2wyeDd4X2dldF9s dXgoaW5kaW9fZGV2KTsNCisJaWYgKGx1eF92YWwgPCAwKSB7DQorCQlkZXZfZXJyKCZjaGlwLT5j bGllbnQtPmRldiwNCisJCSJ0c2wyeDd4X2Fsc19jYWxpYnJhdGUgZmFpbGVkIHRvIGdldCBsdXhc biIpOw0KKwkJcmV0dXJuIGx1eF92YWw7DQorCX0NCisJZ2Fpbl90cmltX3ZhbCA9ICAoKChjaGlw LT50c2wyeDd4X3NldHRpbmdzLmFsc19jYWxfdGFyZ2V0KQ0KKwkJCSogY2hpcC0+dHNsMng3eF9z ZXR0aW5ncy5hbHNfZ2Fpbl90cmltKSAvIGx1eF92YWwpOw0KKw0KKwlpZiAoKGdhaW5fdHJpbV92 YWwgPCAyNTApIHx8IChnYWluX3RyaW1fdmFsID4gNDAwMCkpDQorCQlyZXR1cm4gLUVSQU5HRTsN CisNCisJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5hbHNfZ2Fpbl90cmltID0gZ2Fpbl90cmltX3Zh bDsNCisNCisJZGV2X2luZm8oJmNoaXAtPmNsaWVudC0+ZGV2LA0KKwkJCSIlcyBhbHNfY2FsaWJy YXRlIGNvbXBsZXRlZFxuIiwgY2hpcC0+Y2xpZW50LT5uYW1lKTsNCisNCisJcmV0dXJuIChpbnQp IGdhaW5fdHJpbV92YWw7DQorfQ0KKw0KKy8qDQorICogVHVybiB0aGUgZGV2aWNlIG9uLg0KKyAq IENvbmZpZ3VyYXRpb24gbXVzdCBiZSBzZXQgYmVmb3JlIGNhbGxpbmcgdGhpcyBmdW5jdGlvbi4N CisgKi8NCitzdGF0aWMgaW50IHRzbDJ4N3hfY2hpcF9vbihzdHJ1Y3QgaWlvX2RldiAqaW5kaW9f ZGV2KQ0KK3sNCisJaW50IGk7DQorCWludCByZXQgPSAwOw0KKwl1OCAqZGV2X3JlZzsNCisJdTgg dXRtcDsNCisJaW50IGFsc19jb3VudDsNCisJaW50IGFsc190aW1lOw0KKwlzdHJ1Y3QgdHNsMlg3 WF9jaGlwICpjaGlwID0gaWlvX3ByaXYoaW5kaW9fZGV2KTsNCisJdTggcmVnX3ZhbCA9IDA7DQor DQorCWlmIChjaGlwLT5wZGF0YSAmJiBjaGlwLT5wZGF0YS0+cG93ZXJfb24pDQorCQljaGlwLT5w ZGF0YS0+cG93ZXJfb24oaW5kaW9fZGV2KTsNCisNCisJLyogTm9uIGNhbGN1bGF0ZWQgcGFyYW1l dGVycyAqLw0KKwljaGlwLT50c2wyeDd4X2NvbmZpZ1tUU0wyWDdYX1BSWF9USU1FXSA9DQorCQkJ Y2hpcC0+dHNsMng3eF9zZXR0aW5ncy5wcnhfdGltZTsNCisJY2hpcC0+dHNsMng3eF9jb25maWdb VFNMMlg3WF9XQUlUX1RJTUVdID0NCisJCQljaGlwLT50c2wyeDd4X3NldHRpbmdzLndhaXRfdGlt ZTsNCisJY2hpcC0+dHNsMng3eF9jb25maWdbVFNMMlg3WF9QUlhfQ09ORklHXSA9DQorCQkJY2hp cC0+dHNsMng3eF9zZXR0aW5ncy5wcm94X2NvbmZpZzsNCisNCisJY2hpcC0+dHNsMng3eF9jb25m aWdbVFNMMlg3WF9BTFNfTUlOVEhSRVNITE9dID0NCisJCShjaGlwLT50c2wyeDd4X3NldHRpbmdz LmFsc190aHJlc2hfbG93KSAmIDB4RkY7DQorCWNoaXAtPnRzbDJ4N3hfY29uZmlnW1RTTDJYN1hf QUxTX01JTlRIUkVTSEhJXSA9DQorCQkoY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5hbHNfdGhyZXNo X2xvdyA+PiA4KSAmIDB4RkY7DQorCWNoaXAtPnRzbDJ4N3hfY29uZmlnW1RTTDJYN1hfQUxTX01B WFRIUkVTSExPXSA9DQorCQkoY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5hbHNfdGhyZXNoX2hpZ2gp ICYgMHhGRjsNCisJY2hpcC0+dHNsMng3eF9jb25maWdbVFNMMlg3WF9BTFNfTUFYVEhSRVNISEld ID0NCisJCShjaGlwLT50c2wyeDd4X3NldHRpbmdzLmFsc190aHJlc2hfaGlnaCA+PiA4KSAmIDB4 RkY7DQorCWNoaXAtPnRzbDJ4N3hfY29uZmlnW1RTTDJYN1hfUEVSU0lTVEVOQ0VdID0NCisJCWNo aXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX3BlcnNpc3RlbmNlOw0KKw0KKwljaGlwLT50c2wyeDd4 X2NvbmZpZ1tUU0wyWDdYX1BSWF9DT1VOVF0gPQ0KKwkJCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3Mu cHJveF9wdWxzZV9jb3VudDsNCisJY2hpcC0+dHNsMng3eF9jb25maWdbVFNMMlg3WF9QUlhfTUlO VEhSRVNITE9dID0NCisJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5wcm94X3RocmVzX2xvdzsNCisJ Y2hpcC0+dHNsMng3eF9jb25maWdbVFNMMlg3WF9QUlhfTUFYVEhSRVNITE9dID0NCisJCQljaGlw LT50c2wyeDd4X3NldHRpbmdzLnByb3hfdGhyZXNfaGlnaDsNCisNCisJLyogYW5kIG1ha2Ugc3Vy ZSB3ZSdyZSBub3QgYWxyZWFkeSBvbiAqLw0KKwlpZiAoY2hpcC0+dHNsMng3eF9jaGlwX3N0YXR1 cyA9PSBUU0wyWDdYX0NISVBfV09SS0lORykgew0KKwkJLyogaWYgZm9yY2luZyBhIHJlZ2lzdGVy IHVwZGF0ZSAtIHR1cm4gb2ZmLCB0aGVuIG9uICovDQorCQlkZXZfaW5mbygmY2hpcC0+Y2xpZW50 LT5kZXYsICJkZXZpY2UgaXMgYWxyZWFkeSBlbmFibGVkXG4iKTsNCisJCXJldHVybiAtRUlOVkFM Ow0KKwl9DQorDQorCS8qIGRldGVybWluZSBhbHMgaW50ZWdyYXRpb24gcmVnc3RlciAqLw0KKwlh bHNfY291bnQgPSAoY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5hbHNfdGltZSAqIDEwMCArIDEzNSkg LyAyNzA7DQorCWlmIChhbHNfY291bnQgPT0gMCkNCisJCWFsc19jb3VudCA9IDE7IC8qIGVuc3Vy ZSBhdCBsZWFzdCBvbmUgY3ljbGUgKi8NCisNCisJLyogY29udmVydCBiYWNrIHRvIHRpbWUgKGVu Y29tcGFzc2VzIG92ZXJyaWRlcykgKi8NCisJYWxzX3RpbWUgPSAoYWxzX2NvdW50ICogMjcgKyA1 KSAvIDEwOw0KKwljaGlwLT50c2wyeDd4X2NvbmZpZ1tUU0wyWDdYX0FMU19USU1FXSA9IDI1NiAt IGFsc19jb3VudDsNCisNCisJLyogU2V0IHRoZSBnYWluIGJhc2VkIG9uIHRzbDJ4N3hfc2V0dGlu Z3Mgc3RydWN0ICovDQorCWNoaXAtPnRzbDJ4N3hfY29uZmlnW1RTTDJYN1hfR0FJTl0gPQ0KKwkJ CShjaGlwLT50c2wyeDd4X3NldHRpbmdzLmFsc19nYWluIHwgKG1BMTAwIHwgRElPREUxKQ0KKwkJ CQl8ICgoY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5wcm94X2dhaW4pIDw8IDIpKTsNCisNCisJLyog c2V0IGNoaXAgc3RydWN0IHJlIHNjYWxpbmcgYW5kIHNhdHVyYXRpb24gKi8NCisJY2hpcC0+YWxz X3NhdHVyYXRpb24gPSBhbHNfY291bnQgKiA5MjI7IC8qIDkwJSBvZiBmdWxsIHNjYWxlICovDQor CWNoaXAtPmFsc190aW1lX3NjYWxlID0gKGFsc190aW1lICsgMjUpIC8gNTA7DQorDQorCS8qIFRT TDJYN1ggU3BlY2lmaWMgcG93ZXItb24gLyBhZGMgZW5hYmxlIHNlcXVlbmNlDQorCSAqIFBvd2Vy IG9uIHRoZSBkZXZpY2UgMXN0LiAqLw0KKwl1dG1wID0gVFNMMlg3WF9DTlRMX1BXUl9PTjsNCisJ cmV0ID0gaTJjX3NtYnVzX3dyaXRlX2J5dGVfZGF0YShjaGlwLT5jbGllbnQsDQorCQlUU0wyWDdY X0NNRF9SRUcgfCBUU0wyWDdYX0NOVFJMLCB1dG1wKTsNCisJaWYgKHJldCA8IDApIHsNCisJCWRl dl9lcnIoJmNoaXAtPmNsaWVudC0+ZGV2LCAidHNsMng3eF9jaGlwX29uIGZhaWxlZCBvbiBDTlRS TCByZWcuXG4iKTsNCisJCXJldHVybiAtMTsNCisJfQ0KKw0KKwkvKiBVc2UgdGhlIGZvbGxvd2lu ZyBzaGFkb3cgY29weSBmb3Igb3VyIGRlbGF5IGJlZm9yZSBlbmFibGluZyBBREMuDQorCSAqIFdy aXRlIGFsbCB0aGUgcmVnaXN0ZXJzLiAqLw0KKwlmb3IgKGkgPSAwLCBkZXZfcmVnID0gY2hpcC0+ dHNsMng3eF9jb25maWc7IGkgPCBUU0wyWDdYX1JFR19NQVg7IGkrKykgew0KKwkJcmV0ID0gaTJj X3NtYnVzX3dyaXRlX2J5dGVfZGF0YShjaGlwLT5jbGllbnQsDQorCQkJCVRTTDJYN1hfQ01EX1JF RyArIGksICpkZXZfcmVnKyspOw0KKwkJaWYgKHJldCA8IDApIHsNCisJCQlkZXZfZXJyKCZjaGlw LT5jbGllbnQtPmRldiwNCisJCQkidHNsMng3eF9jaGlwX29uIGZhaWxlZCBvbiB3cml0ZSB0byBy ZWcgJWQuXG4iLCBpKTsNCisJCQlyZXR1cm4gcmV0Ow0KKwkJfQ0KKwl9DQorDQorCXVkZWxheSgz MDAwKTsJLyogUG93ZXItb24gc2V0dGxpbmcgdGltZSAqLw0KKw0KKwkvKiBOT1cgZW5hYmxlIHRo ZSBBREMNCisJICogaW5pdGlhbGl6ZSB0aGUgZGVzaXJlZCBtb2RlIG9mIG9wZXJhdGlvbiAqLw0K Kwl1dG1wID0gVFNMMlg3WF9DTlRMX1BXUl9PTiB8IFRTTDJYN1hfQ05UTF9BRENfRU5CTCB8IENO VExfUFJPWF9ERVRfRU5CTDsNCisJcmV0ID0gaTJjX3NtYnVzX3dyaXRlX2J5dGVfZGF0YShjaGlw LT5jbGllbnQsDQorCQkJVFNMMlg3WF9DTURfUkVHIHwgVFNMMlg3WF9DTlRSTCwgdXRtcCk7DQor CWlmIChyZXQgPCAwKSB7DQorCQlkZXZfZXJyKCZjaGlwLT5jbGllbnQtPmRldiwgInRzbDJ4N3hf Y2hpcF9vbiBmYWlsZWQgb24gMm5kIENUUkwgcmVnLlxuIik7DQorCQlyZXR1cm4gcmV0Ow0KKwkJ fQ0KKw0KKwljaGlwLT50c2wyeDd4X2NoaXBfc3RhdHVzID0gVFNMMlg3WF9DSElQX1dPUktJTkc7 DQorDQorCWlmIChjaGlwLT50c2wyeDd4X3NldHRpbmdzLmludGVycnVwdHNfZW4gIT0gMCkgew0K KwkJZGV2X2luZm8oJmNoaXAtPmNsaWVudC0+ZGV2LCAiU2V0dGluZyBVcCBJbnRlcnJ1cHQocylc biIpOw0KKwkJLyogZmlyc3QgdGltZSBpbnRlcnJ1cHQgKi8NCisJCWNoaXAtPmluaXRfZG9uZSA9 IDA7DQorDQorDQorCXJlZ192YWwgPSBUU0wyWDdYX0NOVExfUFdSX09OOw0KKw0KKwlpZiAoY2hp cC0+dHNsMng3eF9zZXR0aW5ncy5pbnRlcnJ1cHRzX2VuID09IDB4MTApDQorCQlyZWdfdmFsIHw9 IENOVExfQURDX0VOQkw7DQorDQorCWlmIChjaGlwLT50c2wyeDd4X3NldHRpbmdzLmludGVycnVw dHNfZW4gPT0gMHgyMCkNCisJCXJlZ192YWwgfD0gQ05UTF9QUk9YX0RFVF9FTkJMOw0KKw0KKwlp ZiAoY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5pbnRlcnJ1cHRzX2VuID09IDB4MzApDQorCQlyZWdf dmFsIHw9IChDTlRMX0FEQ19FTkJMIHwgQ05UTF9QUk9YX0RFVF9FTkJMKTsNCisNCisJcmVnX3Zh bCB8PSBjaGlwLT50c2wyeDd4X3NldHRpbmdzLmludGVycnVwdHNfZW47DQorDQorCXJldCA9IGky Y19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2hpcC0+Y2xpZW50LA0KKwkJKFRTTDJYN1hfQ01EX1JF RyB8IFRTTDJYN1hfQ05UUkwpLCByZWdfdmFsKTsNCisJaWYgKHJldCA8IDApDQorCQlkZXZfZXJy KCZjaGlwLT5jbGllbnQtPmRldiwNCisJCSJ0c2wyeDd4X2kyY193cml0ZSB0byBkZXZpY2UgZmFp bGVkIGluIHRzbDJ4N3hfSU9DVExfSU5UX1NFVC5cbiIpOw0KKw0KKwkvKiBDbGVhciBvdXQgYW55 IGluaXRpYWwgaW50ZXJydXB0cyAgKi8NCisJcmV0ID0gaTJjX3NtYnVzX3dyaXRlX2J5dGUoY2hp cC0+Y2xpZW50LA0KKwkJVFNMMlg3WF9DTURfUkVHIHwgVFNMMlg3WF9DTURfU1BMX0ZOIHwNCisJ CVRTTDJYN1hfQ01EX1BST1hBTFNfSU5UQ0xSKTsNCisJaWYgKHJldCA8IDApIHsNCisJCWRldl9l cnIoJmNoaXAtPmNsaWVudC0+ZGV2LA0KKwkJCSJ0c2wyeDd4X2kyY193cml0ZV9jb21tYW5kIGZh aWxlZCBpbiB0c2wyeDd4X2NoaXBfb25cbiIpOw0KKwkJcmV0dXJuIHJldDsNCisJCX0NCisJfQ0K KwlyZXR1cm4gcmV0Ow0KKw0KK30NCisNCitzdGF0aWMgaW50IHRzbDJ4N3hfY2hpcF9vZmYoc3Ry dWN0IGlpb19kZXYgKmluZGlvX2RldikNCit7DQorCWludCByZXQ7DQorCXN0cnVjdCB0c2wyWDdY X2NoaXAgKmNoaXAgPSBpaW9fcHJpdihpbmRpb19kZXYpOw0KKw0KKwkvKiB0dXJuIGRldmljZSBv ZmYgKi8NCisJY2hpcC0+dHNsMng3eF9jaGlwX3N0YXR1cyA9IFRTTDJYN1hfQ0hJUF9TVVNQRU5E RUQ7DQorDQorCXJldCA9IGkyY19zbWJ1c193cml0ZV9ieXRlX2RhdGEoY2hpcC0+Y2xpZW50LA0K KwkJVFNMMlg3WF9DTURfUkVHIHwgVFNMMlg3WF9DTlRSTCwgMHgwMCk7DQorDQorCWlmIChjaGlw LT5wZGF0YSAmJiBjaGlwLT5wZGF0YS0+cG93ZXJfb2ZmKQ0KKwkJY2hpcC0+cGRhdGEtPnBvd2Vy X29mZihjaGlwLT5jbGllbnQpOw0KKw0KKwlyZXR1cm4gcmV0Ow0KK30NCisNCisvKioNCisgKiBJ bnRlZ2VyIFNxdWFyZSBSb290DQorICogV2UgbmVlZCBhbiBpbnRlZ2VyIHZlcnNpb24gc2luY2Ug MXN0IEZsb2F0aW5nIHBvaW50IGlzIG5vdCBhbGxvd2VkDQorICogaW4gZHJpdmVyIHdvcmxkLCAy bmQsIGNhbm5vdCBjb3VudCBvbiB0aGUgZGV2aWNlcyBoYXZpbmcgYSBGUFUsIGFuZA0KKyAqIDNy ZCBzb2Z0d2FyZSBGUCBlbXVsYXRpb24gbWF5IGJlIGV4Y2Vzc2l2ZS4NCisgKi8NCitzdGF0aWMg dW5zaWduZWQgbG9uZyB0c2wyeDd4X2lzcXJ0KHVuc2lnbmVkIGxvbmcgeCkNCit7DQorCXJlZ2lz dGVyIHVuc2lnbmVkIGxvbmcgb3AsIHJlcywgb25lOw0KKwlvcCA9IHg7DQorCXJlcyA9IDA7DQor DQorCW9uZSA9IDEgPDwgMzA7DQorCXdoaWxlIChvbmUgPiBvcCkNCisJCW9uZSA+Pj0gMjsNCisN CisJd2hpbGUgKG9uZSAhPSAwKSB7DQorCQlpZiAob3AgPj0gcmVzICsgb25lKSB7DQorCQkJb3Ag LT0gcmVzICsgb25lOw0KKwkJCXJlcyArPSBvbmUgPDwgMTsNCisJCX0NCisJCXJlcyA+Pj0gMTsN CisJCW9uZSA+Pj0gMjsNCisJfQ0KKwlyZXR1cm4gcmVzOw0KK30NCisNCisvKg0KKyAqIFByb3hp bWl0eSBjYWxpYnJhdGlvbiBoZWxwZXIgZnVuY3Rpb24NCisgKiBydW5zIHRocm91Z2ggYSBjb2xs ZWN0aW9uIG9mIGRhdGEgc2FtcGxlcywNCisgKiBzZXRzIHRoZSBtaW4sIG1heCwgbWVhbiwgYW5k IHN0ZCBkZXYuDQorICovDQorc3RhdGljDQordm9pZCB0c2wyeDd4X3Byb3hfY2FsY3VsYXRlKHUx NiAqZGF0YSwgaW50IGxlbmd0aCwgc3RydWN0IHByb3hfc3RhdCAqc3RhdFApDQorew0KKwlpbnQg aTsNCisJaW50IG1pbiwgbWF4LCBzdW0sIG1lYW47DQorCXVuc2lnbmVkIGxvbmcgc3RkZGV2Ow0K KwlpbnQgdG1wOw0KKw0KKwlpZiAobGVuZ3RoID09IDApDQorCQlsZW5ndGggPSAxOw0KKw0KKwlz dW0gPSAwOw0KKwltaW4gPSAweGZmZmY7DQorCW1heCA9IDA7DQorCWZvciAoaSA9IDA7IGkgPCBs ZW5ndGg7IGkrKykgew0KKwkJc3VtICs9IGRhdGFbaV07DQorCQlpZiAoZGF0YVtpXSA8IG1pbikN CisJCQltaW4gPSBkYXRhW2ldOw0KKwkJaWYgKGRhdGFbaV0gPiBtYXgpDQorCQkJbWF4ID0gZGF0 YVtpXTsNCisJfQ0KKwltZWFuID0gc3VtL2xlbmd0aDsNCisJc3RhdFAtPm1pbiA9IG1pbjsNCisJ c3RhdFAtPm1heCA9IG1heDsNCisJc3RhdFAtPm1lYW4gPSBtZWFuOw0KKw0KKwlzdW0gPSAwOw0K Kwlmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHsNCisJCXRtcCA9IGRhdGFbaV0tbWVhbjsN CisJCXN1bSArPSB0bXAgKiB0bXA7DQorCX0NCisJc3RkZGV2ID0gdHNsMng3eF9pc3FydCgobG9u ZylzdW0pL2xlbmd0aDsNCisJc3RhdFAtPnN0ZGRldiA9IHN0ZGRldjsNCisNCit9DQorDQorLyoq DQorICogUHJveGltaXR5IGNhbGlicmF0aW9uIC0gY29sbGVjdHMgYSBudW1iZXIgb2Ygc2FtcGxl cywNCisgKiBjYWxjdWxhdGVzIGEgc3RhbmRhcmQgZGV2aWF0aW9uIGJhc2VkIG9uIHRoZSBzYW1w bGVzLCBhbmQNCisgKiBzZXRzIHRoZSB0aHJlc2hvbGQgYWNjb3JkaW5nbHkuDQorICovDQorc3Rh dGljIHZvaWQgdHNsMng3eF9wcm94X2NhbChzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2KQ0KK3sN CisJdTE2IHByb3hfaGlzdG9yeVtNQVhfU0FNUExFU19DQUwrMV07DQorCWludCBpOw0KKwlzdHJ1 Y3QgcHJveF9zdGF0IHByb3hfc3RhdF9kYXRhWzJdOw0KKwlzdHJ1Y3QgcHJveF9zdGF0ICpjYWxQ Ow0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0gaWlvX3ByaXYoaW5kaW9fZGV2KTsNCisJ dTggdG1wX2lycV9zZXR0aW5nczsNCisJdTggY3VycmVudF9zdGF0ZSA9IGNoaXAtPnRzbDJ4N3hf Y2hpcF9zdGF0dXM7DQorDQorCWlmIChjaGlwLT50c2wyeDd4X3NldHRpbmdzLnByb3hfbWF4X3Nh bXBsZXNfY2FsID4gTUFYX1NBTVBMRVNfQ0FMKSB7DQorCQlkZXZfZXJyKCZjaGlwLT5jbGllbnQt PmRldiwNCisJCQkibWF4IHByb3ggc2FtcGxlcyBjYWwgaXMgdG9vIGJpZzogJWRcbiIsDQorCQkJ Y2hpcC0+dHNsMng3eF9zZXR0aW5ncy5wcm94X21heF9zYW1wbGVzX2NhbCk7DQorCQljaGlwLT50 c2wyeDd4X3NldHRpbmdzLnByb3hfbWF4X3NhbXBsZXNfY2FsID0gTUFYX1NBTVBMRVNfQ0FMOw0K Kwl9DQorDQorCS8qIGhhdmUgdG8gc3RvcCB0byBjaGFuZ2Ugc2V0dGluZ3MgKi8NCisJdHNsMng3 eF9jaGlwX29mZihpbmRpb19kZXYpOw0KKw0KKwkvKiBFbmFibGUgcHJveGltaXR5IGRldGVjdGlv biBzYXZlIGp1c3QgaW4gY2FzZSBwcm94IG5vdCB3YW50ZWQgeWV0Ki8NCisJdG1wX2lycV9zZXR0 aW5ncyA9IGNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuaW50ZXJydXB0c19lbjsNCisJY2hpcC0+dHNs Mng3eF9zZXR0aW5ncy5pbnRlcnJ1cHRzX2VuIHw9IENOVExfUFJPWF9JTlRfRU5CTDsNCisNCisJ Lyp0dXJuIG9uIGRldmljZSBpZiBub3QgYWxyZWFkeSBvbiovDQorCXRzbDJ4N3hfY2hpcF9vbihp bmRpb19kZXYpOw0KKw0KKwkvKmdhdGhlciB0aGUgc2FtcGxlcyovDQorCWZvciAoaSA9IDA7IGkg PCBjaGlwLT50c2wyeDd4X3NldHRpbmdzLnByb3hfbWF4X3NhbXBsZXNfY2FsOyBpKyspIHsNCisJ CW1kZWxheSgxNSk7DQorCQl0c2wyeDd4X3Byb3hfcG9sbChpbmRpb19kZXYpOw0KKwkJcHJveF9o aXN0b3J5W2ldID0gY2hpcC0+cHJveF9jdXJfaW5mby5wcm94X2RhdGE7DQorCQlkZXZfaW5mbygm Y2hpcC0+Y2xpZW50LT5kZXYsICIyIGk9JWQgcHJveCBkYXRhPSAlZFxuIiwNCisJCQlpLCBjaGlw LT5wcm94X2N1cl9pbmZvLnByb3hfZGF0YSk7DQorDQorCX0NCisNCisJdHNsMng3eF9jaGlwX29m ZihpbmRpb19kZXYpOw0KKw0KKwljYWxQID0gJnByb3hfc3RhdF9kYXRhW1BST1hfU1RBVF9DQUxd Ow0KKwl0c2wyeDd4X3Byb3hfY2FsY3VsYXRlKHByb3hfaGlzdG9yeSwNCisJCWNoaXAtPnRzbDJ4 N3hfc2V0dGluZ3MucHJveF9tYXhfc2FtcGxlc19jYWwsIGNhbFApOw0KKwljaGlwLT50c2wyeDd4 X3NldHRpbmdzLnByb3hfdGhyZXNfaGlnaCA9IChjYWxQLT5tYXggPDwgMSkgLSBjYWxQLT5tZWFu Ow0KKw0KKwlkZXZfaW5mbygmY2hpcC0+Y2xpZW50LT5kZXYsICIgY2FsIG1pbj0lZCBtZWFuPSVk IG1heD0lZFxuIiwNCisJCWNhbFAtPm1pbiwgY2FsUC0+bWVhbiwgY2FsUC0+bWF4KTsNCisJZGV2 X2luZm8oJmNoaXAtPmNsaWVudC0+ZGV2LA0KKwkJIiVzIHByb3hpbWl0eSB0aHJlc2hvbGQgc2V0 IHRvICVkXG4iLA0KKwkJY2hpcC0+Y2xpZW50LT5uYW1lLCBjaGlwLT50c2wyeDd4X3NldHRpbmdz LnByb3hfdGhyZXNfaGlnaCk7DQorDQorCS8qIGJhY2sgdG8gdGhlIHdheSB0aGV5IHdlcmUgKi8N CisJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5pbnRlcnJ1cHRzX2VuID0gdG1wX2lycV9zZXR0aW5n czsNCisJaWYgKGN1cnJlbnRfc3RhdGUgPT0gVFNMMlg3WF9DSElQX1dPUktJTkcpDQorCQl0c2wy eDd4X2NoaXBfb24oaW5kaW9fZGV2KTsNCit9DQorDQorLyogLS0tLS0tLS0tLSBTeXNmcyBJbnRl cmZhY2UgRnVuY3Rpb25zIC0tLS0tLS0tLS0tLS0gKi8NCisNCisNCitzdGF0aWMgc3NpemVfdCB0 c2wyeDd4X3Bvd2VyX3N0YXRlX3Nob3coc3RydWN0IGRldmljZSAqZGV2LA0KKwlzdHJ1Y3QgZGV2 aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQ0KK3sNCisJc3RydWN0IGlpb19kZXYgKmRl dl9pbmZvID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQorCXN0cnVjdCB0c2wyWDdYX2NoaXAgKmNo aXAgPSBpaW9fcHJpdihkZXZfaW5mbyk7DQorDQorCXJldHVybiBzbnByaW50ZihidWYsIFBBR0Vf U0laRSwgIiVkXG4iLCBjaGlwLT50c2wyeDd4X2NoaXBfc3RhdHVzKTsNCit9DQorDQorc3RhdGlj IHNzaXplX3QgdHNsMng3eF9wb3dlcl9zdGF0ZV9zdG9yZShzdHJ1Y3QgZGV2aWNlICpkZXYsDQor CXN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjb25zdCBjaGFyICpidWYsIHNpemVfdCBs ZW4pDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2X2luZm8gPSBkZXZfZ2V0X2RydmRhdGEoZGV2 KTsNCisJdW5zaWduZWQgbG9uZyB2YWx1ZTsNCisNCisJaWYgKGtzdHJ0b3VsKGJ1ZiwgMCwgJnZh bHVlKSkNCisJCXJldHVybiAtRUlOVkFMOw0KKw0KKwlpZiAodmFsdWUgPT0gMCkNCisJCXRzbDJ4 N3hfY2hpcF9vZmYoZGV2X2luZm8pOw0KKwllbHNlDQorCQl0c2wyeDd4X2NoaXBfb24oZGV2X2lu Zm8pOw0KKw0KKwlyZXR1cm4gbGVuOw0KK30NCisNCitzdGF0aWMgc3NpemVfdCB0c2wyeDd4X3By b3hpbWl0eV9kZXRlY3Rfc2hvdyhzdHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZpY2Vf YXR0cmlidXRlICphdHRyLCBjaGFyICpidWYpDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2X2lu Zm8gPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAqY2hpcCA9 IGlpb19wcml2KGRldl9pbmZvKTsNCisNCisJdHNsMng3eF9wcm94X3BvbGwoZGV2X2luZm8pOw0K Kw0KKwlyZXR1cm4gc25wcmludGYoYnVmLCBQQUdFX1NJWkUsICIlZFxuIiwNCisJCQljaGlwLT5w cm94X2N1cl9pbmZvLnByb3hfZXZlbnQpOw0KK30NCisNCitzdGF0aWMgc3NpemVfdCB0c2wyeDd4 X2dhaW5fc2hvdyhzdHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZpY2VfYXR0cmlidXRl ICphdHRyLCBjaGFyICpidWYpDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2X2luZm8gPSBkZXZf Z2V0X2RydmRhdGEoZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAqY2hpcCA9IGlpb19wcml2 KGRldl9pbmZvKTsNCisNCisJcmV0dXJuIHNucHJpbnRmKGJ1ZiwgUEFHRV9TSVpFLCAiJWRcbiIs DQorCQl0c2wyWDdYX2Fsc19nYWluYWRqW2NoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX2dhaW5d LmNoMCk7DQorfQ0KKw0KK3N0YXRpYyBzc2l6ZV90IHRzbDJ4N3hfZ2Fpbl9zdG9yZShzdHJ1Y3Qg ZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjb25zdCBjaGFy ICpidWYsIHNpemVfdCBsZW4pDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2X2luZm8gPSBkZXZf Z2V0X2RydmRhdGEoZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAqY2hpcCA9IGlpb19wcml2 KGRldl9pbmZvKTsNCisJdW5zaWduZWQgbG9uZyB2YWx1ZTsNCisJaWYgKGtzdHJ0b3VsKGJ1Ziwg MCwgJnZhbHVlKSkNCisJCXJldHVybiAtRUlOVkFMOw0KKw0KKwlzd2l0Y2ggKHZhbHVlKSB7DQor CWNhc2UgMToNCisJCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX2dhaW4gPSAwOw0KKwkJYnJl YWs7DQorCWNhc2UgODoNCisJCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX2dhaW4gPSAxOw0K KwkJYnJlYWs7DQorCWNhc2UgMTY6DQorCQljaGlwLT50c2wyeDd4X3NldHRpbmdzLmFsc19nYWlu ID0gMjsNCisJCWJyZWFrOw0KKwljYXNlIDEyMDoNCisJCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3Mu YWxzX2dhaW4gPSAzOw0KKwkJYnJlYWs7DQorCWNhc2UgMTI4Og0KKwkJY2hpcC0+dHNsMng3eF9z ZXR0aW5ncy5hbHNfZ2FpbiA9IDM7DQorCQlicmVhazsNCisNCisJZGVmYXVsdDoNCisJCWRldl9l cnIoZGV2LA0KKwkJCSJJbnZhbGlkIEdhaW4gSW5kZXhcbiIpOw0KKwkJcmV0dXJuIC1FSU5WQUw7 DQorCX0NCisNCisJcmV0dXJuIGxlbjsNCit9DQorDQorc3RhdGljIHNzaXplX3QgdHNsMng3eF9n YWluX2F2YWlsYWJsZV9zaG93KHN0cnVjdCBkZXZpY2UgKmRldiwNCisJc3RydWN0IGRldmljZV9h dHRyaWJ1dGUgKmF0dHIsIGNoYXIgKmJ1ZikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5m byA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0g aWlvX3ByaXYoZGV2X2luZm8pOw0KKw0KKwlpZiAoc3RybmNtcChjaGlwLT5jbGllbnQtPm5hbWUs ICJ0c2wyNzcyIiwgNykgPT0gMCkNCisJCXJldHVybiBzbnByaW50ZihidWYsIFBBR0VfU0laRSwg IiVzXG4iLCAiMSA4IDE2IDEyOCIpOw0KKwllbHNlDQorCQlyZXR1cm4gc25wcmludGYoYnVmLCBQ QUdFX1NJWkUsICIlc1xuIiwgIjEgOCAxNiAxMjAiKTsNCit9DQorDQorc3RhdGljIHNzaXplX3Qg dHNsMng3eF9wcm94X2dhaW5fc2hvdyhzdHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZp Y2VfYXR0cmlidXRlICphdHRyLCBjaGFyICpidWYpDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2 X2luZm8gPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAqY2hp cCA9IGlpb19wcml2KGRldl9pbmZvKTsNCisNCisJcmV0dXJuIHNucHJpbnRmKGJ1ZiwgUEFHRV9T SVpFLCAiJWRcbiIsDQorCQkJKDEgPDwgY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5wcm94X2dhaW4p KTsNCit9DQorDQorc3RhdGljIHNzaXplX3QgdHNsMng3eF9wcm94X2dhaW5fc3RvcmUoc3RydWN0 IGRldmljZSAqZGV2LA0KKwlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY29uc3QgY2hh ciAqYnVmLCBzaXplX3QgbGVuKQ0KK3sNCisJc3RydWN0IGlpb19kZXYgKmRldl9pbmZvID0gZGV2 X2dldF9kcnZkYXRhKGRldik7DQorCXN0cnVjdCB0c2wyWDdYX2NoaXAgKmNoaXAgPSBpaW9fcHJp dihkZXZfaW5mbyk7DQorCXVuc2lnbmVkIGxvbmcgdmFsdWU7DQorCWlmIChrc3RydG91bChidWYs IDAsICZ2YWx1ZSkpDQorCQlyZXR1cm4gLUVJTlZBTDsNCisNCisJc3dpdGNoICh2YWx1ZSkgew0K KwljYXNlIDE6DQorCQljaGlwLT50c2wyeDd4X3NldHRpbmdzLnByb3hfZ2FpbiA9IDA7DQorCQli cmVhazsNCisJY2FzZSAyOg0KKwkJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5wcm94X2dhaW4gPSAx Ow0KKwkJYnJlYWs7DQorCWNhc2UgNDoNCisJCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MucHJveF9n YWluID0gMjsNCisJCWJyZWFrOw0KKwljYXNlIDg6DQorCQljaGlwLT50c2wyeDd4X3NldHRpbmdz LnByb3hfZ2FpbiA9IDM7DQorCQlicmVhazsNCisJZGVmYXVsdDoNCisJCWRldl9lcnIoZGV2LA0K KwkJCSJJbnZhbGlkIFByb3ggR2FpbiBJbmRleFxuIik7DQorCQlyZXR1cm4gLUVJTlZBTDsNCisJ fQ0KKw0KKwlyZXR1cm4gbGVuOw0KK30NCisNCitzdGF0aWMgc3NpemVfdCB0c2wyeDd4X3Byb3hf Z2Fpbl9hdmFpbGFibGVfc2hvdyhzdHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZpY2Vf YXR0cmlidXRlICphdHRyLCBjaGFyICpidWYpDQorew0KKwkJcmV0dXJuIHNucHJpbnRmKGJ1Ziwg UEFHRV9TSVpFLCAiJXNcbiIsICIxIDIgNCA4Iik7DQorfQ0KKw0KK3N0YXRpYyBzc2l6ZV90IHRz bDJ4N3hfYWxzX3RpbWVfc2hvdyhzdHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZpY2Vf YXR0cmlidXRlICphdHRyLCBjaGFyICpidWYpDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2X2lu Zm8gPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAqY2hpcCA9 IGlpb19wcml2KGRldl9pbmZvKTsNCisNCisJcmV0dXJuIHNucHJpbnRmKGJ1ZiwgUEFHRV9TSVpF LCAiJWRcbiIsDQorCQkJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5hbHNfdGltZSk7DQorfQ0KKw0K K3N0YXRpYyBzc2l6ZV90IHRzbDJ4N3hfYWxzX3RpbWVfc3RvcmUoc3RydWN0IGRldmljZSAqZGV2 LA0KKwlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY29uc3QgY2hhciAqYnVmLCBzaXpl X3QgbGVuKQ0KK3sNCisJc3RydWN0IGlpb19kZXYgKmRldl9pbmZvID0gZGV2X2dldF9kcnZkYXRh KGRldik7DQorCXN0cnVjdCB0c2wyWDdYX2NoaXAgKmNoaXAgPSBpaW9fcHJpdihkZXZfaW5mbyk7 DQorCXVuc2lnbmVkIGxvbmcgdmFsdWU7DQorDQorCWlmIChrc3RydG91bChidWYsIDAsICZ2YWx1 ZSkpDQorCQlyZXR1cm4gLUVJTlZBTDsNCisNCisJaWYgKCh2YWx1ZSA8IDUwKSB8fCAodmFsdWUg PiA2NTApKQ0KKwkJcmV0dXJuIC1FSU5WQUw7DQorDQorCWlmICh2YWx1ZSAlIDUwKQ0KKwkJcmV0 dXJuIC1FSU5WQUw7DQorDQorCSBjaGlwLT50c2wyeDd4X3NldHRpbmdzLmFsc190aW1lID0gdmFs dWU7DQorDQorCXJldHVybiBsZW47DQorfQ0KKw0KK3N0YXRpYyBzc2l6ZV90IHRzbDJ4N3hfYWxz X3RpbWVfYXZhaWxhYmxlX3Nob3coc3RydWN0IGRldmljZSAqZGV2LA0KKwlzdHJ1Y3QgZGV2aWNl X2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQ0KK3sNCisJcmV0dXJuIHNucHJpbnRmKGJ1Ziwg UEFHRV9TSVpFLCAiJXNcbiIsDQorCQkiNTAgMTAwIDE1MCAyMDAgMjUwIDMwMCAzNTAgNDAwIDQ1 MCA1MDAgNTUwIDYwMCA2NTAiKTsNCit9DQorDQorc3RhdGljIHNzaXplX3QgdHNsMng3eF9hbHNf dHJpbV9zaG93KHN0cnVjdCBkZXZpY2UgKmRldiwNCisJc3RydWN0IGRldmljZV9hdHRyaWJ1dGUg KmF0dHIsIGNoYXIgKmJ1ZikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5mbyA9IGRldl9n ZXRfZHJ2ZGF0YShkZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0gaWlvX3ByaXYo ZGV2X2luZm8pOw0KKw0KKwlyZXR1cm4gc25wcmludGYoYnVmLCBQQUdFX1NJWkUsICIlZFxuIiwN CisJCQljaGlwLT50c2wyeDd4X3NldHRpbmdzLmFsc19nYWluX3RyaW0pOw0KK30NCisNCitzdGF0 aWMgc3NpemVfdCB0c2wyeDd4X2Fsc190cmltX3N0b3JlKHN0cnVjdCBkZXZpY2UgKmRldiwNCisJ c3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90IGxl bikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5mbyA9IGRldl9nZXRfZHJ2ZGF0YShkZXYp Ow0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0gaWlvX3ByaXYoZGV2X2luZm8pOw0KKwl1 bnNpZ25lZCBsb25nIHZhbHVlOw0KKw0KKwlpZiAoa3N0cnRvdWwoYnVmLCAwLCAmdmFsdWUpKQ0K KwkJcmV0dXJuIC1FSU5WQUw7DQorDQorCWlmICh2YWx1ZSkNCisJCWNoaXAtPnRzbDJ4N3hfc2V0 dGluZ3MuYWxzX2dhaW5fdHJpbSA9IHZhbHVlOw0KKw0KKwlyZXR1cm4gbGVuOw0KK30NCisNCitz dGF0aWMgc3NpemVfdCB0c2wyeDd4X2Fsc19jYWxfdGFyZ2V0X3Nob3coc3RydWN0IGRldmljZSAq ZGV2LA0KKwlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQ0KK3sNCisJ c3RydWN0IGlpb19kZXYgKmRldl9pbmZvID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQorCXN0cnVj dCB0c2wyWDdYX2NoaXAgKmNoaXAgPSBpaW9fcHJpdihkZXZfaW5mbyk7DQorDQorCXJldHVybiBz bnByaW50ZihidWYsIFBBR0VfU0laRSwgIiVkXG4iLA0KKwkJCWNoaXAtPnRzbDJ4N3hfc2V0dGlu Z3MuYWxzX2NhbF90YXJnZXQpOw0KK30NCisNCitzdGF0aWMgc3NpemVfdCB0c2wyeDd4X2Fsc19j YWxfdGFyZ2V0X3N0b3JlKHN0cnVjdCBkZXZpY2UgKmRldiwNCisJc3RydWN0IGRldmljZV9hdHRy aWJ1dGUgKmF0dHIsIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90IGxlbikNCit7DQorCXN0cnVjdCBp aW9fZGV2ICpkZXZfaW5mbyA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3 WF9jaGlwICpjaGlwID0gaWlvX3ByaXYoZGV2X2luZm8pOw0KKwl1bnNpZ25lZCBsb25nIHZhbHVl Ow0KKw0KKwlpZiAoa3N0cnRvdWwoYnVmLCAwLCAmdmFsdWUpKQ0KKwkJcmV0dXJuIC1FSU5WQUw7 DQorDQorCWlmICh2YWx1ZSkNCisJCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX2NhbF90YXJn ZXQgPSB2YWx1ZTsNCisNCisJcmV0dXJuIGxlbjsNCit9DQorDQorc3RhdGljIHNzaXplX3QgdHNs Mng3eF9pbnRlcnJ1cHRzX2VuX3Nob3coc3RydWN0IGRldmljZSAqZGV2LA0KKwlzdHJ1Y3QgZGV2 aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQ0KK3sNCisJc3RydWN0IGlpb19kZXYgKmRl dl9pbmZvID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQorCXN0cnVjdCB0c2wyWDdYX2NoaXAgKmNo aXAgPSBpaW9fcHJpdihkZXZfaW5mbyk7DQorDQorCWlmIChjaGlwLT50c2wyeDd4X3NldHRpbmdz LmludGVycnVwdHNfZW4gJiAweDEwKQ0KKwkJcmV0dXJuIHNucHJpbnRmKGJ1ZiwgUEFHRV9TSVpF LCAiJWRcbiIsIDEpOw0KKwllbHNlDQorCQlyZXR1cm4gc25wcmludGYoYnVmLCBQQUdFX1NJWkUs ICIlZFxuIiwgMCk7DQorfQ0KKw0KK3N0YXRpYyBzc2l6ZV90IHRzbDJ4N3hfaW50ZXJydXB0c19l bl9zdG9yZShzdHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICph dHRyLCBjb25zdCBjaGFyICpidWYsIHNpemVfdCBsZW4pDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAq ZGV2X2luZm8gPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAq Y2hpcCA9IGlpb19wcml2KGRldl9pbmZvKTsNCisJdW5zaWduZWQgbG9uZyB2YWx1ZTsNCisNCisJ aWYgKGtzdHJ0b3VsKGJ1ZiwgMCwgJnZhbHVlKSkNCisJCXJldHVybiAtRUlOVkFMOw0KKw0KKwlp ZiAodmFsdWUgPiAxKQ0KKwkJcmV0dXJuIC1FSU5WQUw7DQorCWlmICh2YWx1ZSkNCisJCWNoaXAt PnRzbDJ4N3hfc2V0dGluZ3MuaW50ZXJydXB0c19lbiB8PSAweDEwOw0KKwllbHNlDQorCQljaGlw LT50c2wyeDd4X3NldHRpbmdzLmludGVycnVwdHNfZW4gJj0gMHgyMDsNCisNCisJcmV0dXJuIGxl bjsNCit9DQorDQorc3RhdGljIHNzaXplX3QgdHNsMng3eF9wcm94X2ludGVycnVwdF9zaG93KHN0 cnVjdCBkZXZpY2UgKmRldiwNCisJc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNoYXIg KmJ1ZikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5mbyA9IGRldl9nZXRfZHJ2ZGF0YShk ZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0gaWlvX3ByaXYoZGV2X2luZm8pOw0K Kw0KKwlpZiAoY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5pbnRlcnJ1cHRzX2VuICYgMHgyMCkNCisJ CXJldHVybiBzbnByaW50ZihidWYsIFBBR0VfU0laRSwgIiVkXG4iLCAxKTsNCisJZWxzZQ0KKwkJ cmV0dXJuIHNucHJpbnRmKGJ1ZiwgUEFHRV9TSVpFLCAiJWRcbiIsIDApOw0KK30NCisNCitzdGF0 aWMgc3NpemVfdCB0c2wyeDd4X3Byb3hfaW50ZXJydXB0X3N0b3JlKHN0cnVjdCBkZXZpY2UgKmRl diwNCisJc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6 ZV90IGxlbikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5mbyA9IGRldl9nZXRfZHJ2ZGF0 YShkZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0gaWlvX3ByaXYoZGV2X2luZm8p Ow0KKwl1bnNpZ25lZCBsb25nIHZhbHVlOw0KKw0KKwlpZiAoa3N0cnRvdWwoYnVmLCAwLCAmdmFs dWUpKQ0KKwkJcmV0dXJuIC1FSU5WQUw7DQorDQorCWlmICh2YWx1ZSA+IDEpDQorCQlyZXR1cm4g LUVJTlZBTDsNCisJaWYgKHZhbHVlKQ0KKwkJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5pbnRlcnJ1 cHRzX2VuIHw9IDB4MjA7DQorCWVsc2UNCisJCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuaW50ZXJy dXB0c19lbiAmPSAweDEwOw0KKw0KKwlyZXR1cm4gbGVuOw0KK30NCisNCitzdGF0aWMgc3NpemVf dCB0c2wyeDd4X2Fsc190aHJlc2hfbG93X3Nob3coc3RydWN0IGRldmljZSAqZGV2LA0KKwlzdHJ1 Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQ0KK3sNCisJc3RydWN0IGlpb19k ZXYgKmRldl9pbmZvID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQorCXN0cnVjdCB0c2wyWDdYX2No aXAgKmNoaXAgPSBpaW9fcHJpdihkZXZfaW5mbyk7DQorDQorCXJldHVybiBzbnByaW50ZihidWYs IFBBR0VfU0laRSwgIiVkXG4iLA0KKwkJCWNoaXAtPnRzbDJ4N3hfc2V0dGluZ3MuYWxzX3RocmVz aF9sb3cpOw0KK30NCisNCitzdGF0aWMgc3NpemVfdCB0c2wyeDd4X2Fsc190aHJlc2hfbG93X3N0 b3JlKHN0cnVjdCBkZXZpY2UgKmRldiwNCisJc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIs IGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90IGxlbikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZf aW5mbyA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlw ID0gaWlvX3ByaXYoZGV2X2luZm8pOw0KKwl1bnNpZ25lZCBsb25nIHZhbHVlOw0KKw0KKwlpZiAo a3N0cnRvdWwoYnVmLCAwLCAmdmFsdWUpKQ0KKwkJcmV0dXJuIC1FSU5WQUw7DQorDQorCWNoaXAt PnRzbDJ4N3hfc2V0dGluZ3MuYWxzX3RocmVzaF9sb3cgPSB2YWx1ZTsNCisNCisJcmV0dXJuIGxl bjsNCit9DQorDQorc3RhdGljIHNzaXplX3QgdHNsMng3eF9hbHNfdGhyZXNoX2hpZ2hfc2hvdyhz dHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjaGFy ICpidWYpDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2X2luZm8gPSBkZXZfZ2V0X2RydmRhdGEo ZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAqY2hpcCA9IGlpb19wcml2KGRldl9pbmZvKTsN CisNCisJcmV0dXJuIHNucHJpbnRmKGJ1ZiwgUEFHRV9TSVpFLCAiJWRcbiIsDQorCQkJY2hpcC0+ dHNsMng3eF9zZXR0aW5ncy5hbHNfdGhyZXNoX2hpZ2gpOw0KK30NCisNCitzdGF0aWMgc3NpemVf dCB0c2wyeDd4X2Fsc190aHJlc2hfaGlnaF9zdG9yZShzdHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0 cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjb25zdCBjaGFyICpidWYsIHNpemVfdCBsZW4p DQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2X2luZm8gPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsN CisJc3RydWN0IHRzbDJYN1hfY2hpcCAqY2hpcCA9IGlpb19wcml2KGRldl9pbmZvKTsNCisJdW5z aWduZWQgbG9uZyB2YWx1ZTsNCisNCisJaWYgKGtzdHJ0b3VsKGJ1ZiwgMCwgJnZhbHVlKSkNCisJ CXJldHVybiAtRUlOVkFMOw0KKw0KKwljaGlwLT50c2wyeDd4X3NldHRpbmdzLmFsc190aHJlc2hf aGlnaCA9IHZhbHVlOw0KKw0KKwlyZXR1cm4gbGVuOw0KK30NCisNCitzdGF0aWMgc3NpemVfdCB0 c2wyeDd4X3Byb3hfdGhyZXNoX2xvd19zaG93KHN0cnVjdCBkZXZpY2UgKmRldiwNCisJc3RydWN0 IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNoYXIgKmJ1ZikNCit7DQorCXN0cnVjdCBpaW9fZGV2 ICpkZXZfaW5mbyA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlw ICpjaGlwID0gaWlvX3ByaXYoZGV2X2luZm8pOw0KKw0KKwlyZXR1cm4gc25wcmludGYoYnVmLCBQ QUdFX1NJWkUsICIlZFxuIiwNCisJCQljaGlwLT50c2wyeDd4X3NldHRpbmdzLnByb3hfdGhyZXNf bG93KTsNCit9DQorDQorc3RhdGljIHNzaXplX3QgdHNsMng3eF9wcm94X3RocmVzaF9sb3dfc3Rv cmUoc3RydWN0IGRldmljZSAqZGV2LA0KKwlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwg Y29uc3QgY2hhciAqYnVmLCBzaXplX3QgbGVuKQ0KK3sNCisJc3RydWN0IGlpb19kZXYgKmRldl9p bmZvID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQorCXN0cnVjdCB0c2wyWDdYX2NoaXAgKmNoaXAg PSBpaW9fcHJpdihkZXZfaW5mbyk7DQorCXVuc2lnbmVkIGxvbmcgdmFsdWU7DQorDQorCWlmIChr c3RydG91bChidWYsIDAsICZ2YWx1ZSkpDQorCQlyZXR1cm4gLUVJTlZBTDsNCisNCisJY2hpcC0+ dHNsMng3eF9zZXR0aW5ncy5wcm94X3RocmVzX2xvdyA9IHZhbHVlOw0KKw0KKwlyZXR1cm4gbGVu Ow0KK30NCisNCitzdGF0aWMgc3NpemVfdCB0c2wyeDd4X3Byb3hfdGhyZXNoX2hpZ2hfc2hvdyhz dHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZpY2VfYXR0cmlidXRlICphdHRyLCBjaGFy ICpidWYpDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2X2luZm8gPSBkZXZfZ2V0X2RydmRhdGEo ZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAqY2hpcCA9IGlpb19wcml2KGRldl9pbmZvKTsN CisNCisJcmV0dXJuIHNucHJpbnRmKGJ1ZiwgUEFHRV9TSVpFLCAiJWRcbiIsDQorCQkJY2hpcC0+ dHNsMng3eF9zZXR0aW5ncy5wcm94X3RocmVzX2hpZ2gpOw0KK30NCisNCitzdGF0aWMgc3NpemVf dCB0c2wyeDd4X3Byb3hfdGhyZXNoX2hpZ2hfc3RvcmUoc3RydWN0IGRldmljZSAqZGV2LA0KKwlz dHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY29uc3QgY2hhciAqYnVmLCBzaXplX3QgbGVu KQ0KK3sNCisJc3RydWN0IGlpb19kZXYgKmRldl9pbmZvID0gZGV2X2dldF9kcnZkYXRhKGRldik7 DQorCXN0cnVjdCB0c2wyWDdYX2NoaXAgKmNoaXAgPSBpaW9fcHJpdihkZXZfaW5mbyk7DQorCXVu c2lnbmVkIGxvbmcgdmFsdWU7DQorDQorCWlmIChrc3RydG91bChidWYsIDAsICZ2YWx1ZSkpDQor CQlyZXR1cm4gLUVJTlZBTDsNCisNCisJY2hpcC0+dHNsMng3eF9zZXR0aW5ncy5wcm94X3RocmVz X2hpZ2ggPSB2YWx1ZTsNCisNCisJcmV0dXJuIGxlbjsNCit9DQorDQorc3RhdGljIHNzaXplX3Qg dHNsMng3eF9wcm94X2RhdGFfc2hvdyhzdHJ1Y3QgZGV2aWNlICpkZXYsDQorCXN0cnVjdCBkZXZp Y2VfYXR0cmlidXRlICphdHRyLCBjaGFyICpidWYpDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAqZGV2 X2luZm8gPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAqY2hp cCA9IGlpb19wcml2KGRldl9pbmZvKTsNCisJdHNsMng3eF9wcm94X3BvbGwoZGV2X2luZm8pOw0K Kw0KKwlyZXR1cm4gc25wcmludGYoYnVmLCBQQUdFX1NJWkUsICIlZFxuIiwNCisJCQljaGlwLT5w cm94X2N1cl9pbmZvLnByb3hfZGF0YSk7DQorfQ0KKw0KKy8qIHNhbXBsaW5nX2ZyZXF1ZW5jeSBB S0EgcGVyc2lzdGVuY2UgaW4gZGF0YSBzaGVldCAqLw0KK3N0YXRpYyBzc2l6ZV90IHRzbDJ4N3hf YWxzX3BlcnNpc3RlbmNlX3Nob3coc3RydWN0IGRldmljZSAqZGV2LA0KKwlzdHJ1Y3QgZGV2aWNl X2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQ0KK3sNCisJc3RydWN0IGlpb19kZXYgKmRldl9p bmZvID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQorCXN0cnVjdCB0c2wyWDdYX2NoaXAgKmNoaXAg PSBpaW9fcHJpdihkZXZfaW5mbyk7DQorDQorCXJldHVybiBzbnByaW50ZihidWYsIFBBR0VfU0la RSwgIjB4JTAyWFxuIiwNCisJCQljaGlwLT50c2wyeDd4X3NldHRpbmdzLmFsc19wZXJzaXN0ZW5j ZSk7DQorfQ0KKw0KK3N0YXRpYyBzc2l6ZV90IHRzbDJ4N3hfYWxzX3BlcnNpc3RlbmNlX3N0b3Jl KHN0cnVjdCBkZXZpY2UgKmRldiwNCisJc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNv bnN0IGNoYXIgKmJ1Ziwgc2l6ZV90IGxlbikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5m byA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0g aWlvX3ByaXYoZGV2X2luZm8pOw0KKwl1bnNpZ25lZCBsb25nIHZhbHVlOw0KKw0KKwlpZiAoa3N0 cnRvdWwoYnVmLCAwLCAmdmFsdWUpKQ0KKwkJcmV0dXJuIC1FSU5WQUw7DQorDQorCWNoaXAtPnRz bDJ4N3hfc2V0dGluZ3MuYWxzX3BlcnNpc3RlbmNlID0gdmFsdWU7DQorDQorCXJldHVybiBsZW47 DQorfQ0KKw0KK3N0YXRpYw0KK3NzaXplX3QgdHNsMng3eF9hbHNfcGVyc2lzdGVuY2VfYXZhaWxh YmxlX3Nob3coc3RydWN0IGRldmljZSAqZGV2LA0KKwlzdHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAq YXR0ciwgY2hhciAqYnVmKQ0KK3sNCisJcmV0dXJuIHNucHJpbnRmKGJ1ZiwgUEFHRV9TSVpFLCAi MHgwMCAtIDB4RkYgKDAgLSAyNTUpXG4iKTsNCit9DQorDQorc3RhdGljDQorc3NpemVfdCB0c2wy eDd4X2x1eF9zaG93KHN0cnVjdCBkZXZpY2UgKmRldiwgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUg KmF0dHIsDQorCWNoYXIgKmJ1ZikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5mbyA9IGRl dl9nZXRfZHJ2ZGF0YShkZXYpOw0KKwlpbnQgbHV4Ow0KKw0KKwlsdXggPSB0c2wyeDd4X2dldF9s dXgoZGV2X2luZm8pOw0KKw0KKwlyZXR1cm4gc25wcmludGYoYnVmLCBQQUdFX1NJWkUsICIlZFxu IiwgbHV4KTsNCit9DQorDQorc3RhdGljDQorc3NpemVfdCB0c2wyeDd4X2FkY19zaG93KHN0cnVj dCBkZXZpY2UgKmRldiwgc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsDQorCWNoYXIgKmJ1 ZikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5mbyA9IGRldl9nZXRfZHJ2ZGF0YShkZXYp Ow0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0gaWlvX3ByaXYoZGV2X2luZm8pOw0KKw0K Kwl0c2wyeDd4X2dldF9sdXgoZGV2X2luZm8pOw0KKw0KKwlyZXR1cm4gc25wcmludGYoYnVmLCBQ QUdFX1NJWkUsICIweCUwOHhcbiIsDQorCQkJKChjaGlwLT5hbHNfY3VyX2luZm8uYWxzX2NoMCA8 PCAxNikgfA0KKwkJCQkJY2hpcC0+YWxzX2N1cl9pbmZvLmFsc19jaDEpKTsNCit9DQorDQorc3Rh dGljIHNzaXplX3QgdHNsMng3eF9kb19jYWxpYnJhdGUoc3RydWN0IGRldmljZSAqZGV2LA0KKwlz dHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY29uc3QgY2hhciAqYnVmLCBzaXplX3QgbGVu KQ0KK3sNCisJc3RydWN0IGlpb19kZXYgKmRldl9pbmZvID0gZGV2X2dldF9kcnZkYXRhKGRldik7 DQorCXVuc2lnbmVkIGxvbmcgdmFsdWU7DQorDQorCWlmIChrc3RydG91bChidWYsIDAsICZ2YWx1 ZSkpDQorCQlyZXR1cm4gLUVJTlZBTDsNCisNCisJaWYgKHZhbHVlID09IDEpDQorCQl0c2wyeDd4 X2Fsc19jYWxpYnJhdGUoZGV2X2luZm8pOw0KKw0KKwlyZXR1cm4gbGVuOw0KK30NCisNCitzdGF0 aWMgc3NpemVfdCB0c2wyeDd4X2x1eHRhYmxlX3Nob3coc3RydWN0IGRldmljZSAqZGV2LA0KKwlz dHJ1Y3QgZGV2aWNlX2F0dHJpYnV0ZSAqYXR0ciwgY2hhciAqYnVmKQ0KK3sNCisJc3RydWN0IGlp b19kZXYgKmRldl9pbmZvID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQorCXN0cnVjdCB0c2wyWDdY X2NoaXAgKmNoaXAgPSBpaW9fcHJpdihkZXZfaW5mbyk7DQorCWludCBpOw0KKwlpbnQgb2Zmc2V0 ID0gMDsNCisNCisJaSA9IDA7DQorCXdoaWxlIChpIDwgKE1BWF9UQUJMRV9TSVpFICogMykpIHsN CisJCW9mZnNldCArPSBzbnByaW50ZihidWYgKyBvZmZzZXQsIFBBR0VfU0laRSwgIiVkLCVkLCVk LCIsDQorCQkJY2hpcC0+dHNsMng3eF9kZXZpY2VfbHV4W2ldLnJhdGlvLA0KKwkJCWNoaXAtPnRz bDJ4N3hfZGV2aWNlX2x1eFtpXS5jaDAsDQorCQkJY2hpcC0+dHNsMng3eF9kZXZpY2VfbHV4W2ld LmNoMSk7DQorCQlpZiAoY2hpcC0+dHNsMng3eF9kZXZpY2VfbHV4W2ldLnJhdGlvID09IDApIHsN CisJCQkvKiBXZSBqdXN0IHByaW50ZWQgdGhlIGZpcnN0ICIwIiBlbnRyeS4NCisJCQkgKiBOb3cg Z2V0IHJpZCBvZiB0aGUgZXh0cmEgIiwiIGFuZCBicmVhay4gKi8NCisJCQlvZmZzZXQtLTsNCisJ CQlicmVhazsNCisJCX0NCisJCWkrKzsNCisJfQ0KKw0KKwlvZmZzZXQgKz0gc25wcmludGYoYnVm ICsgb2Zmc2V0LCBQQUdFX1NJWkUsICJcbiIpOw0KKwlyZXR1cm4gb2Zmc2V0Ow0KK30NCisNCitz dGF0aWMgc3NpemVfdCB0c2wyeDd4X2x1eHRhYmxlX3N0b3JlKHN0cnVjdCBkZXZpY2UgKmRldiwN CisJc3RydWN0IGRldmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90 IGxlbikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5mbyA9IGRldl9nZXRfZHJ2ZGF0YShk ZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0gaWlvX3ByaXYoZGV2X2luZm8pOw0K KwlpbnQgdmFsdWVbQVJSQVlfU0laRShjaGlwLT50c2wyeDd4X2RldmljZV9sdXgpKjMgKyAxXTsN CisJaW50IG47DQorDQorCWdldF9vcHRpb25zKGJ1ZiwgQVJSQVlfU0laRSh2YWx1ZSksIHZhbHVl KTsNCisNCisJLyogV2Ugbm93IGhhdmUgYW4gYXJyYXkgb2YgaW50cyBzdGFydGluZyBhdCB2YWx1 ZVsxXSwgYW5kDQorCSAqIGVudW1lcmF0ZWQgYnkgdmFsdWVbMF0uDQorCSAqIFdlIGV4cGVjdCBl YWNoIGdyb3VwIG9mIHRocmVlIGludHMgaXMgb25lIHRhYmxlIGVudHJ5LA0KKwkgKiBhbmQgdGhl IGxhc3QgdGFibGUgZW50cnkgaXMgYWxsIDAuDQorCSAqLw0KKwluID0gdmFsdWVbMF07DQorCWlm ICgobiAlIDMpIHx8IG4gPCA2IHx8DQorCQkJbiA+ICgoQVJSQVlfU0laRShjaGlwLT50c2wyeDd4 X2RldmljZV9sdXgpIC0gMSkgKiAzKSkgew0KKwkJZGV2X2luZm8oZGV2LCAiTFVYIFRBQkxFIElO UFVUIEVSUk9SIDEgVmFsdWVbMF09JWRcbiIsIG4pOw0KKwkJcmV0dXJuIC1FSU5WQUw7DQorCX0N CisNCisJaWYgKCh2YWx1ZVsobiAtIDIpXSB8IHZhbHVlWyhuIC0gMSldIHwgdmFsdWVbbl0pICE9 IDApIHsNCisJCWRldl9pbmZvKGRldiwgIkxVWCBUQUJMRSBJTlBVVCBFUlJPUiAyIFZhbHVlWzBd PSVkXG4iLCBuKTsNCisJCXJldHVybiAtRUlOVkFMOw0KKwl9DQorDQorCWlmIChjaGlwLT50c2wy eDd4X2NoaXBfc3RhdHVzID09IFRTTDJYN1hfQ0hJUF9XT1JLSU5HKQ0KKwkJdHNsMng3eF9jaGlw X29mZihkZXZfaW5mbyk7DQorDQorCS8qIFplcm8gb3V0IHRoZSB0YWJsZSAqLw0KKwltZW1zZXQo Y2hpcC0+dHNsMng3eF9kZXZpY2VfbHV4LCAwLCBzaXplb2YoY2hpcC0+dHNsMng3eF9kZXZpY2Vf bHV4KSk7DQorCW1lbWNweShjaGlwLT50c2wyeDd4X2RldmljZV9sdXgsICZ2YWx1ZVsxXSwgKHZh bHVlWzBdICogNCkpOw0KKw0KKwlyZXR1cm4gbGVuOw0KK30NCisNCitzdGF0aWMgc3NpemVfdCB0 c2wyeDd4X2RvX3Byb3hfY2FsaWJyYXRlKHN0cnVjdCBkZXZpY2UgKmRldiwNCisJc3RydWN0IGRl dmljZV9hdHRyaWJ1dGUgKmF0dHIsIGNvbnN0IGNoYXIgKmJ1Ziwgc2l6ZV90IGxlbikNCit7DQor CXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5mbyA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KKwl1bnNp Z25lZCBsb25nIHZhbHVlOw0KKw0KKwlpZiAoa3N0cnRvdWwoYnVmLCAwLCAmdmFsdWUpKQ0KKwkJ cmV0dXJuIC1FSU5WQUw7DQorDQorCWlmICh2YWx1ZSA9PSAxKQ0KKwkJdHNsMng3eF9wcm94X2Nh bChkZXZfaW5mbyk7DQorDQorCXJldHVybiBsZW47DQorfQ0KKw0KK3N0YXRpYyBERVZJQ0VfQVRU Uihwb3dlcl9zdGF0ZSwgU19JUlVHTyB8IFNfSVdVU1IsDQorCQl0c2wyeDd4X3Bvd2VyX3N0YXRl X3Nob3csIHRzbDJ4N3hfcG93ZXJfc3RhdGVfc3RvcmUpOw0KKw0KK3N0YXRpYyBERVZJQ0VfQVRU Uihwcm94aW1pdHlfcmF3LCBTX0lSVUdPLA0KKwkJdHNsMng3eF9wcm94aW1pdHlfZGV0ZWN0X3No b3csIE5VTEwpOw0KKw0KK3N0YXRpYyBERVZJQ0VfQVRUUihpbnRlbnNpdHlfaW5mcmFyZWRfcmF3 LCBTX0lSVUdPLA0KKwkJdHNsMng3eF9wcm94X2RhdGFfc2hvdywgTlVMTCk7DQorDQorDQorc3Rh dGljIERFVklDRV9BVFRSKHByb3hpbWl0eV9jYWxpYnNjYWxlLCBTX0lSVUdPIHwgU19JV1VTUiwN CisJCXRzbDJ4N3hfcHJveF9nYWluX3Nob3csIHRzbDJ4N3hfcHJveF9nYWluX3N0b3JlKTsNCitz dGF0aWMgREVWSUNFX0FUVFIocHJveGltaXR5X2NhbGlic2NhbGVfYXZhaWxhYmxlLCBTX0lSVUdP LA0KKwkJdHNsMng3eF9wcm94X2dhaW5fYXZhaWxhYmxlX3Nob3csIE5VTEwpOw0KKw0KK3N0YXRp YyBERVZJQ0VfQVRUUihpbGx1bWluYW5jZTBfY2FsaWJzY2FsZSwgU19JUlVHTyB8IFNfSVdVU1Is DQorCQl0c2wyeDd4X2dhaW5fc2hvdywgdHNsMng3eF9nYWluX3N0b3JlKTsNCitzdGF0aWMgREVW SUNFX0FUVFIoaWxsdW1pbmFuY2UwX2NhbGlic2NhbGVfYXZhaWxhYmxlLCBTX0lSVUdPLA0KKwkJ dHNsMng3eF9nYWluX2F2YWlsYWJsZV9zaG93LCBOVUxMKTsNCisNCitzdGF0aWMgREVWSUNFX0FU VFIoaWxsdW1pbmFuY2UwX2ludGVncmF0aW9uX3RpbWUsIFNfSVJVR08gfCBTX0lXVVNSLA0KKwkJ dHNsMng3eF9hbHNfdGltZV9zaG93LCB0c2wyeDd4X2Fsc190aW1lX3N0b3JlKTsNCitzdGF0aWMg REVWSUNFX0FUVFIoaWxsdW1pbmFuY2UwX2ludGVncmF0aW9uX3RpbWVfYXZhaWxhYmxlLCBTX0lS VUdPLA0KKwkJdHNsMng3eF9hbHNfdGltZV9hdmFpbGFibGVfc2hvdywgTlVMTCk7DQorDQorc3Rh dGljIERFVklDRV9BVFRSKGlsbHVtaW5hbmNlMF9jYWxpYmJpYXMsIFNfSVJVR08gfCBTX0lXVVNS LA0KKwkJdHNsMng3eF9hbHNfdHJpbV9zaG93LCB0c2wyeDd4X2Fsc190cmltX3N0b3JlKTsNCisN CitzdGF0aWMgREVWSUNFX0FUVFIoaWxsdW1pbmFuY2UwX2lucHV0X3RhcmdldCwgU19JUlVHTyB8 IFNfSVdVU1IsDQorCQl0c2wyeDd4X2Fsc19jYWxfdGFyZ2V0X3Nob3csIHRzbDJ4N3hfYWxzX2Nh bF90YXJnZXRfc3RvcmUpOw0KKw0KK3N0YXRpYyBERVZJQ0VfQVRUUihpbGx1bWluYW5jZTBfYm90 aF9yYXcsIFNfSVJVR08sIHRzbDJ4N3hfYWRjX3Nob3csDQorCQlOVUxMKTsNCisNCitzdGF0aWMg REVWSUNFX0FUVFIoaWxsdW1pbmFuY2UwX2lucHV0LCBTX0lSVUdPLCB0c2wyeDd4X2x1eF9zaG93 LA0KKwkJTlVMTCk7DQorc3RhdGljIERFVklDRV9BVFRSKGlsbHVtaW5hbmNlMF9jYWxpYnJhdGUs IFNfSVdVU1IsIE5VTEwsDQorCQl0c2wyeDd4X2RvX2NhbGlicmF0ZSk7DQorc3RhdGljIERFVklD RV9BVFRSKHByb3hpbWl0eV9jYWxpYnJhdGUsIFNfSVdVU1IsIE5VTEwsDQorCQl0c2wyeDd4X2Rv X3Byb3hfY2FsaWJyYXRlKTsNCisNCitzdGF0aWMgREVWSUNFX0FUVFIoaWxsdW1pbmFuY2UwX2x1 eF90YWJsZSwgU19JUlVHTyB8IFNfSVdVU1IsDQorCQl0c2wyeDd4X2x1eHRhYmxlX3Nob3csIHRz bDJ4N3hfbHV4dGFibGVfc3RvcmUpOw0KKw0KK3N0YXRpYyBERVZJQ0VfQVRUUihpbGx1bWluYW5j ZTBfdGhyZXNoX2ZhbGxpbmdfdmFsdWUsIFNfSVJVR08gfCBTX0lXVVNSLA0KKwkJdHNsMng3eF9h bHNfdGhyZXNoX2xvd19zaG93LCB0c2wyeDd4X2Fsc190aHJlc2hfbG93X3N0b3JlKTsNCisNCitz dGF0aWMgREVWSUNFX0FUVFIoaWxsdW1pbmFuY2UwX3RocmVzaF9yaXNpbmdfdmFsdWUsIFNfSVJV R08gfCBTX0lXVVNSLA0KKwkJdHNsMng3eF9hbHNfdGhyZXNoX2hpZ2hfc2hvdywgdHNsMng3eF9h bHNfdGhyZXNoX2hpZ2hfc3RvcmUpOw0KKw0KK3N0YXRpYyBERVZJQ0VfQVRUUihzYW1wbGluZ19m cmVxdWVuY3ksIFNfSVJVR08gfCBTX0lXVVNSLA0KKwkJdHNsMng3eF9hbHNfcGVyc2lzdGVuY2Vf c2hvdywgdHNsMng3eF9hbHNfcGVyc2lzdGVuY2Vfc3RvcmUpOw0KKw0KK3N0YXRpYyBERVZJQ0Vf QVRUUihzYW1wbGluZ19mcmVxdWVuY3lfYXZhaWxhYmxlLCBTX0lSVUdPLA0KKwkJdHNsMng3eF9h bHNfcGVyc2lzdGVuY2VfYXZhaWxhYmxlX3Nob3csIE5VTEwpOw0KKw0KK3N0YXRpYyBERVZJQ0Vf QVRUUihwcm94aW1pdHlfdGhyZXNoX3Jpc2luZ192YWx1ZSwgU19JUlVHTyB8IFNfSVdVU1IsDQor CQl0c2wyeDd4X3Byb3hfdGhyZXNoX2hpZ2hfc2hvdywgdHNsMng3eF9wcm94X3RocmVzaF9oaWdo X3N0b3JlKTsNCisNCitzdGF0aWMgREVWSUNFX0FUVFIocHJveGltaXR5X3RocmVzaF9mYWxsaW5n X3ZhbHVlLCBTX0lSVUdPIHwgU19JV1VTUiwNCisJCXRzbDJ4N3hfcHJveF90aHJlc2hfbG93X3No b3csIHRzbDJ4N3hfcHJveF90aHJlc2hfbG93X3N0b3JlKTsNCisNCitzdGF0aWMgc3RydWN0IGF0 dHJpYnV0ZSAqdHNsMjU3MV9kZXZpY2VfYXR0cnNbXSA9IHsNCisJJmRldl9hdHRyX3Bvd2VyX3N0 YXRlLmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfY2FsaWJzY2FsZS5hdHRyLA0KKwkm ZGV2X2F0dHJfaWxsdW1pbmFuY2UwX2NhbGlic2NhbGVfYXZhaWxhYmxlLmF0dHIsDQorCSZkZXZf YXR0cl9pbGx1bWluYW5jZTBfaW50ZWdyYXRpb25fdGltZS5hdHRyLA0KKwkmZGV2X2F0dHJfaWxs dW1pbmFuY2UwX2ludGVncmF0aW9uX3RpbWVfYXZhaWxhYmxlLmF0dHIsDQorCSZkZXZfYXR0cl9p bGx1bWluYW5jZTBfY2FsaWJiaWFzLmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfaW5w dXRfdGFyZ2V0LmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfYm90aF9yYXcuYXR0ciwN CisJJmRldl9hdHRyX2lsbHVtaW5hbmNlMF9pbnB1dC5hdHRyLA0KKwkmZGV2X2F0dHJfaWxsdW1p bmFuY2UwX2NhbGlicmF0ZS5hdHRyLA0KKwkmZGV2X2F0dHJfaWxsdW1pbmFuY2UwX2x1eF90YWJs ZS5hdHRyLA0KKwkmZGV2X2F0dHJfaWxsdW1pbmFuY2UwX3RocmVzaF9mYWxsaW5nX3ZhbHVlLmF0 dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfdGhyZXNoX3Jpc2luZ192YWx1ZS5hdHRyLA0K KwkmZGV2X2F0dHJfc2FtcGxpbmdfZnJlcXVlbmN5LmF0dHIsDQorCSZkZXZfYXR0cl9zYW1wbGlu Z19mcmVxdWVuY3lfYXZhaWxhYmxlLmF0dHIsDQorCU5VTEwNCit9Ow0KKw0KK3N0YXRpYyBzdHJ1 Y3QgYXR0cmlidXRlICp0c2wyNjcxX2RldmljZV9hdHRyc1tdID0gew0KKwkmZGV2X2F0dHJfcG93 ZXJfc3RhdGUuYXR0ciwNCisJJmRldl9hdHRyX3Byb3hpbWl0eV9yYXcuYXR0ciwNCisJJmRldl9h dHRyX2ludGVuc2l0eV9pbmZyYXJlZF9yYXcuYXR0ciwNCisJJmRldl9hdHRyX3NhbXBsaW5nX2Zy ZXF1ZW5jeS5hdHRyLA0KKwkmZGV2X2F0dHJfc2FtcGxpbmdfZnJlcXVlbmN5X2F2YWlsYWJsZS5h dHRyLA0KKwkmZGV2X2F0dHJfcHJveGltaXR5X3RocmVzaF9yaXNpbmdfdmFsdWUuYXR0ciwNCisJ JmRldl9hdHRyX3Byb3hpbWl0eV90aHJlc2hfZmFsbGluZ192YWx1ZS5hdHRyLA0KKwkmZGV2X2F0 dHJfcHJveGltaXR5X2NhbGlicmF0ZS5hdHRyLA0KKwlOVUxMDQorfTsNCisNCitzdGF0aWMgc3Ry dWN0IGF0dHJpYnV0ZSAqdHNsMjc3MV9kZXZpY2VfYXR0cnNbXSA9IHsNCisJJmRldl9hdHRyX3Bv d2VyX3N0YXRlLmF0dHIsDQorCSZkZXZfYXR0cl9wcm94aW1pdHlfcmF3LmF0dHIsDQorCSZkZXZf YXR0cl9pbnRlbnNpdHlfaW5mcmFyZWRfcmF3LmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5j ZTBfY2FsaWJzY2FsZS5hdHRyLA0KKwkmZGV2X2F0dHJfaWxsdW1pbmFuY2UwX2NhbGlic2NhbGVf YXZhaWxhYmxlLmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfaW50ZWdyYXRpb25fdGlt ZS5hdHRyLA0KKwkmZGV2X2F0dHJfaWxsdW1pbmFuY2UwX2ludGVncmF0aW9uX3RpbWVfYXZhaWxh YmxlLmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfY2FsaWJiaWFzLmF0dHIsDQorCSZk ZXZfYXR0cl9pbGx1bWluYW5jZTBfaW5wdXRfdGFyZ2V0LmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1 bWluYW5jZTBfYm90aF9yYXcuYXR0ciwNCisJJmRldl9hdHRyX2lsbHVtaW5hbmNlMF9pbnB1dC5h dHRyLA0KKwkmZGV2X2F0dHJfaWxsdW1pbmFuY2UwX2NhbGlicmF0ZS5hdHRyLA0KKwkmZGV2X2F0 dHJfaWxsdW1pbmFuY2UwX2x1eF90YWJsZS5hdHRyLA0KKwkmZGV2X2F0dHJfaWxsdW1pbmFuY2Uw X3RocmVzaF9mYWxsaW5nX3ZhbHVlLmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfdGhy ZXNoX3Jpc2luZ192YWx1ZS5hdHRyLA0KKwkmZGV2X2F0dHJfc2FtcGxpbmdfZnJlcXVlbmN5LmF0 dHIsDQorCSZkZXZfYXR0cl9zYW1wbGluZ19mcmVxdWVuY3lfYXZhaWxhYmxlLmF0dHIsDQorCSZk ZXZfYXR0cl9wcm94aW1pdHlfdGhyZXNoX3Jpc2luZ192YWx1ZS5hdHRyLA0KKwkmZGV2X2F0dHJf cHJveGltaXR5X3RocmVzaF9mYWxsaW5nX3ZhbHVlLmF0dHIsDQorCSZkZXZfYXR0cl9wcm94aW1p dHlfY2FsaWJyYXRlLmF0dHIsDQorCU5VTEwNCit9Ow0KKw0KK3N0YXRpYyBzdHJ1Y3QgYXR0cmli dXRlICp0c2wyNTcyX2RldmljZV9hdHRyc1tdID0gew0KKwkmZGV2X2F0dHJfcG93ZXJfc3RhdGUu YXR0ciwNCisJJmRldl9hdHRyX2lsbHVtaW5hbmNlMF9jYWxpYnNjYWxlLmF0dHIsDQorCSZkZXZf YXR0cl9pbGx1bWluYW5jZTBfY2FsaWJzY2FsZV9hdmFpbGFibGUuYXR0ciwNCisJJmRldl9hdHRy X2lsbHVtaW5hbmNlMF9pbnRlZ3JhdGlvbl90aW1lLmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWlu YW5jZTBfaW50ZWdyYXRpb25fdGltZV9hdmFpbGFibGUuYXR0ciwNCisJJmRldl9hdHRyX2lsbHVt aW5hbmNlMF9jYWxpYmJpYXMuYXR0ciwNCisJJmRldl9hdHRyX2lsbHVtaW5hbmNlMF9pbnB1dF90 YXJnZXQuYXR0ciwNCisJJmRldl9hdHRyX2lsbHVtaW5hbmNlMF9ib3RoX3Jhdy5hdHRyLA0KKwkm ZGV2X2F0dHJfaWxsdW1pbmFuY2UwX2lucHV0LmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5j ZTBfY2FsaWJyYXRlLmF0dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfbHV4X3RhYmxlLmF0 dHIsDQorCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfdGhyZXNoX2ZhbGxpbmdfdmFsdWUuYXR0ciwN CisJJmRldl9hdHRyX2lsbHVtaW5hbmNlMF90aHJlc2hfcmlzaW5nX3ZhbHVlLmF0dHIsDQorCSZk ZXZfYXR0cl9zYW1wbGluZ19mcmVxdWVuY3kuYXR0ciwNCisJJmRldl9hdHRyX3NhbXBsaW5nX2Zy ZXF1ZW5jeV9hdmFpbGFibGUuYXR0ciwNCisJTlVMTA0KK307DQorDQorc3RhdGljIHN0cnVjdCBh dHRyaWJ1dGUgKnRzbDI2NzJfZGV2aWNlX2F0dHJzW10gPSB7DQorCSZkZXZfYXR0cl9wb3dlcl9z dGF0ZS5hdHRyLA0KKwkmZGV2X2F0dHJfcHJveGltaXR5X3Jhdy5hdHRyLA0KKwkmZGV2X2F0dHJf aW50ZW5zaXR5X2luZnJhcmVkX3Jhdy5hdHRyLA0KKwkmZGV2X2F0dHJfcHJveGltaXR5X2NhbGli c2NhbGUuYXR0ciwNCisJJmRldl9hdHRyX3NhbXBsaW5nX2ZyZXF1ZW5jeS5hdHRyLA0KKwkmZGV2 X2F0dHJfc2FtcGxpbmdfZnJlcXVlbmN5X2F2YWlsYWJsZS5hdHRyLA0KKwkmZGV2X2F0dHJfcHJv eGltaXR5X3RocmVzaF9yaXNpbmdfdmFsdWUuYXR0ciwNCisJJmRldl9hdHRyX3Byb3hpbWl0eV90 aHJlc2hfZmFsbGluZ192YWx1ZS5hdHRyLA0KKwkmZGV2X2F0dHJfcHJveGltaXR5X2NhbGlicmF0 ZS5hdHRyLA0KKwlOVUxMDQorfTsNCisNCitzdGF0aWMgc3RydWN0IGF0dHJpYnV0ZSAqdHNsMjc3 Ml9kZXZpY2VfYXR0cnNbXSA9IHsNCisJCSZkZXZfYXR0cl9wb3dlcl9zdGF0ZS5hdHRyLA0KKwkJ JmRldl9hdHRyX3Byb3hpbWl0eV9yYXcuYXR0ciwNCisJCSZkZXZfYXR0cl9wcm94aW1pdHlfY2Fs aWJzY2FsZS5hdHRyLA0KKwkJJmRldl9hdHRyX2ludGVuc2l0eV9pbmZyYXJlZF9yYXcuYXR0ciwN CisJCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfY2FsaWJzY2FsZS5hdHRyLA0KKwkJJmRldl9hdHRy X2lsbHVtaW5hbmNlMF9jYWxpYnNjYWxlX2F2YWlsYWJsZS5hdHRyLA0KKwkJJmRldl9hdHRyX2ls bHVtaW5hbmNlMF9pbnRlZ3JhdGlvbl90aW1lLmF0dHIsDQorCQkmZGV2X2F0dHJfaWxsdW1pbmFu Y2UwX2ludGVncmF0aW9uX3RpbWVfYXZhaWxhYmxlLmF0dHIsDQorCQkmZGV2X2F0dHJfaWxsdW1p bmFuY2UwX2NhbGliYmlhcy5hdHRyLA0KKwkJJmRldl9hdHRyX2lsbHVtaW5hbmNlMF9pbnB1dF90 YXJnZXQuYXR0ciwNCisJCSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfYm90aF9yYXcuYXR0ciwNCisJ CSZkZXZfYXR0cl9pbGx1bWluYW5jZTBfaW5wdXQuYXR0ciwNCisJCSZkZXZfYXR0cl9pbGx1bWlu YW5jZTBfY2FsaWJyYXRlLmF0dHIsDQorCQkmZGV2X2F0dHJfaWxsdW1pbmFuY2UwX2x1eF90YWJs ZS5hdHRyLA0KKwkJJmRldl9hdHRyX2lsbHVtaW5hbmNlMF90aHJlc2hfZmFsbGluZ192YWx1ZS5h dHRyLA0KKwkJJmRldl9hdHRyX2lsbHVtaW5hbmNlMF90aHJlc2hfcmlzaW5nX3ZhbHVlLmF0dHIs DQorCQkmZGV2X2F0dHJfc2FtcGxpbmdfZnJlcXVlbmN5LmF0dHIsDQorCQkmZGV2X2F0dHJfc2Ft cGxpbmdfZnJlcXVlbmN5X2F2YWlsYWJsZS5hdHRyLA0KKwkJJmRldl9hdHRyX3Byb3hpbWl0eV90 aHJlc2hfcmlzaW5nX3ZhbHVlLmF0dHIsDQorCQkmZGV2X2F0dHJfcHJveGltaXR5X3RocmVzaF9m YWxsaW5nX3ZhbHVlLmF0dHIsDQorCQkmZGV2X2F0dHJfcHJveGltaXR5X2NhbGlicmF0ZS5hdHRy LA0KKwkJJmRldl9hdHRyX3Byb3hpbWl0eV9jYWxpYnNjYWxlX2F2YWlsYWJsZS5hdHRyLA0KKwkJ TlVMTA0KK307DQorDQorc3RhdGljIHN0cnVjdCBhdHRyaWJ1dGVfZ3JvdXAgdHNsMlg3WF9kZXZf YXR0cl9ncm91cF90YmxbXSA9IHsNCisJW3RzbDI1NzFdID0gew0KKwkJLmF0dHJzID0gdHNsMjU3 MV9kZXZpY2VfYXR0cnMsDQorCX0sDQorCVt0c2wyNjcxXSA9IHsNCisJCS5hdHRycyA9IHRzbDI2 NzFfZGV2aWNlX2F0dHJzLA0KKwl9LA0KKwlbdG1kMjY3MV0gPSB7DQorCQkuYXR0cnMgPSB0c2wy NjcxX2RldmljZV9hdHRycywNCisJfSwNCisJW3RzbDI3NzFdID0gew0KKwkJLmF0dHJzID0gdHNs Mjc3MV9kZXZpY2VfYXR0cnMsDQorCX0sDQorCVt0bWQyNzcxXSA9IHsNCisJCS5hdHRycyA9IHRz bDI3NzFfZGV2aWNlX2F0dHJzLA0KKwl9LA0KKwlbdHNsMjU3Ml0gPSB7DQorCQkuYXR0cnMgPSB0 c2wyNTcyX2RldmljZV9hdHRycywNCisJfSwNCisJW3RzbDI2NzJdID0gew0KKwkJLmF0dHJzID0g dHNsMjY3Ml9kZXZpY2VfYXR0cnMsDQorCX0sDQorCVt0bWQyNjcyXSA9IHsNCisJCS5hdHRycyA9 IHRzbDI2NzJfZGV2aWNlX2F0dHJzLA0KKwl9LA0KKwlbdHNsMjc3Ml0gPSB7DQorCQkuYXR0cnMg PSB0c2wyNzcyX2RldmljZV9hdHRycywNCisJfSwNCisJW3RtZDI3NzJdID0gew0KKwkJLmF0dHJz ID0gdHNsMjc3Ml9kZXZpY2VfYXR0cnMsDQorCX0sDQorDQorfTsNCisNCitzdGF0aWMgSUlPX0RF VklDRV9BVFRSKGlsbHVtaW5hbmNlX3RocmVzaF9ib3RoX2VuLA0KKwkJU19JUlVHTyB8IFNfSVdV U1IsDQorCQl0c2wyeDd4X2ludGVycnVwdHNfZW5fc2hvdywgdHNsMng3eF9pbnRlcnJ1cHRzX2Vu X3N0b3JlLCAwKTsNCisNCitzdGF0aWMgSUlPX0RFVklDRV9BVFRSKHByb3hpbWl0eV90aHJlc2hf Ym90aF9lbiwNCisJCVNfSVJVR08gfCBTX0lXVVNSLA0KKwkJdHNsMng3eF9wcm94X2ludGVycnVw dF9zaG93LCB0c2wyeDd4X3Byb3hfaW50ZXJydXB0X3N0b3JlLCAwKTsNCisNCitzdGF0aWMgc3Ry dWN0IGF0dHJpYnV0ZSAqdHNsMlg3WF9wcm94X2V2ZW50X2F0dHJpYnV0ZXNbXSA9IHsNCisJJmlp b19kZXZfYXR0cl9wcm94aW1pdHlfdGhyZXNoX2JvdGhfZW4uZGV2X2F0dHIuYXR0ciwNCisJTlVM TCwNCit9Ow0KKw0KK3N0YXRpYyBzdHJ1Y3QgYXR0cmlidXRlICp0c2wyWDdYX2Fsc19ldmVudF9h dHRyaWJ1dGVzW10gPSB7DQorCSZpaW9fZGV2X2F0dHJfaWxsdW1pbmFuY2VfdGhyZXNoX2JvdGhf ZW4uZGV2X2F0dHIuYXR0ciwNCisJTlVMTCwNCit9Ow0KKw0KK3N0YXRpYyBzdHJ1Y3QgYXR0cmli dXRlICp0c2wyWDdYX3Byb3hhbHNfZXZlbnRfYXR0cmlidXRlc1tdID0gew0KKwkmaWlvX2Rldl9h dHRyX2lsbHVtaW5hbmNlX3RocmVzaF9ib3RoX2VuLmRldl9hdHRyLmF0dHIsDQorCSZpaW9fZGV2 X2F0dHJfcHJveGltaXR5X3RocmVzaF9ib3RoX2VuLmRldl9hdHRyLmF0dHIsDQorCU5VTEwsDQor fTsNCisNCitzdGF0aWMgc3RydWN0IGF0dHJpYnV0ZV9ncm91cCB0c2wyWDdYX2V2ZW50X2F0dHJf Z3JvdXBfdGJsW10gPSB7DQorCVt0c2wyNTcxXSA9IHsNCisJCS5hdHRycyA9IHRzbDJYN1hfYWxz X2V2ZW50X2F0dHJpYnV0ZXMsDQorCQkubmFtZSAgPSAiZXZlbnRzIiwNCisJfSwNCisJW3RzbDI2 NzFdID0gew0KKwkJLmF0dHJzID0gdHNsMlg3WF9wcm94X2V2ZW50X2F0dHJpYnV0ZXMsDQorCQku bmFtZSAgPSAiZXZlbnRzIiwNCisJfSwNCisJW3RtZDI2NzFdID0gew0KKwkJLmF0dHJzID0gdHNs Mlg3WF9wcm94X2V2ZW50X2F0dHJpYnV0ZXMsDQorCQkubmFtZSAgPSAiZXZlbnRzIiwNCisJfSwN CisJW3RzbDI3NzFdID0gew0KKwkJLmF0dHJzID0gdHNsMlg3WF9wcm94YWxzX2V2ZW50X2F0dHJp YnV0ZXMsDQorCQkubmFtZSAgPSAiZXZlbnRzIiwNCisJfSwNCisJW3RtZDI3NzFdID0gew0KKwkJ LmF0dHJzID0gdHNsMlg3WF9wcm94YWxzX2V2ZW50X2F0dHJpYnV0ZXMsDQorCQkubmFtZSAgPSAi ZXZlbnRzIiwNCisJfSwNCisNCisJW3RzbDI1NzJdID0gew0KKwkJLmF0dHJzID0gdHNsMlg3WF9h bHNfZXZlbnRfYXR0cmlidXRlcywNCisJCS5uYW1lICA9ICJldmVudHMiLA0KKwl9LA0KKwlbdHNs MjY3Ml0gPSB7DQorCQkuYXR0cnMgPSB0c2wyWDdYX3Byb3hfZXZlbnRfYXR0cmlidXRlcywNCisJ CS5uYW1lICA9ICJldmVudHMiLA0KKwl9LA0KKwlbdG1kMjY3Ml0gPSB7DQorCQkuYXR0cnMgPSB0 c2wyWDdYX3Byb3hfZXZlbnRfYXR0cmlidXRlcywNCisJCS5uYW1lICA9ICJldmVudHMiLA0KKwl9 LA0KKwlbdHNsMjc3Ml0gPSB7DQorCQkuYXR0cnMgPSB0c2wyWDdYX3Byb3hhbHNfZXZlbnRfYXR0 cmlidXRlcywNCisJCS5uYW1lICA9ICJldmVudHMiLA0KKwl9LA0KKwlbdG1kMjc3Ml0gPSB7DQor CQkuYXR0cnMgPSB0c2wyWDdYX3Byb3hhbHNfZXZlbnRfYXR0cmlidXRlcywNCisJCS5uYW1lICA9 ICJldmVudHMiLA0KKwl9DQorfTsNCisNCisNCisvKiBVc2UgdGhlIGRlZmF1bHQgcmVnaXN0ZXIg dmFsdWVzIHRvIGlkZW50aWZ5IHRoZSBUYW9zIGRldmljZSAqLw0KK3N0YXRpYyBpbnQgdHNsMng3 eF9kZXZpY2VfaWQodW5zaWduZWQgY2hhciAqYnVmcCwgaW50IHRhcmdldCkNCit7DQorCXN3aXRj aCAodGFyZ2V0KSB7DQorCWNhc2UgdHNsMjU3MToNCisJY2FzZSB0c2wyNjcxOg0KKwljYXNlIHRz bDI3NzE6DQorCQlyZXR1cm4gKChidWZwW1RTTDJYN1hfQ0hJUElEXSAmIDB4ZjApID09IFRSSVRP Tl9JRCk7DQorCWJyZWFrOw0KKwljYXNlIHRtZDI2NzE6DQorCWNhc2UgdG1kMjc3MToNCisJCXJl dHVybiAoKGJ1ZnBbVFNMMlg3WF9DSElQSURdICYgMHhmMCkgPT0gSEFMSUJVVF9JRCk7DQorCWJy ZWFrOw0KKwljYXNlIHRzbDI1NzI6DQorCWNhc2UgdHNsMjY3MjoNCisJY2FzZSB0bWQyNjcyOg0K KwljYXNlIHRzbDI3NzI6DQorCWNhc2UgdG1kMjc3MjoNCisJCXJldHVybiAoKGJ1ZnBbVFNMMlg3 WF9DSElQSURdICYgMHhmMCkgPT0gU1dPUkRGSVNIX0lEKTsNCisJYnJlYWs7DQorCX0NCisNCisJ cmV0dXJuIC1FSU5WQUw7DQorfQ0KKw0KK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaWlvX2luZm8gdHNs Mlg3WF9pbmZvW10gPSB7DQorCVt0c2wyNTcxXSA9IHsNCisJCQkuYXR0cnMgPSAmdHNsMlg3WF9k ZXZfYXR0cl9ncm91cF90YmxbdHNsMjU3MV0sDQorCQkJLmV2ZW50X2F0dHJzID0gJnRzbDJYN1hf ZXZlbnRfYXR0cl9ncm91cF90YmxbdHNsMjU3MV0sDQorCQkJLmRyaXZlcl9tb2R1bGUgPSBUSElT X01PRFVMRSwNCisJfSwNCisJW3RzbDI2NzFdID0gew0KKwkJCS5hdHRycyA9ICZ0c2wyWDdYX2Rl dl9hdHRyX2dyb3VwX3RibFt0c2wyNjcxXSwNCisJCQkuZXZlbnRfYXR0cnMgPSAmdHNsMlg3WF9l dmVudF9hdHRyX2dyb3VwX3RibFt0c2wyNjcxXSwNCisJCQkuZHJpdmVyX21vZHVsZSA9IFRISVNf TU9EVUxFLA0KKwl9LA0KKwlbdG1kMjY3MV0gPSB7DQorCQkJLmF0dHJzID0gJnRzbDJYN1hfZGV2 X2F0dHJfZ3JvdXBfdGJsW3RzbDI2NzFdLA0KKwkJCS5ldmVudF9hdHRycyA9ICZ0c2wyWDdYX2V2 ZW50X2F0dHJfZ3JvdXBfdGJsW3RzbDI2NzFdLA0KKwkJCS5kcml2ZXJfbW9kdWxlID0gVEhJU19N T0RVTEUsDQorCX0sDQorCVt0c2wyNzcxXSA9IHsNCisJCQkuYXR0cnMgPSAmdHNsMlg3WF9kZXZf YXR0cl9ncm91cF90YmxbdHNsMjc3MV0sDQorCQkJLmV2ZW50X2F0dHJzID0gJnRzbDJYN1hfZXZl bnRfYXR0cl9ncm91cF90YmxbdHNsMjc3MV0sDQorCQkJLmRyaXZlcl9tb2R1bGUgPSBUSElTX01P RFVMRSwNCisJfSwNCisJW3RtZDI3NzFdID0gew0KKwkJCS5hdHRycyA9ICZ0c2wyWDdYX2Rldl9h dHRyX2dyb3VwX3RibFt0c2wyNzcxXSwNCisJCQkuZXZlbnRfYXR0cnMgPSAmdHNsMlg3WF9ldmVu dF9hdHRyX2dyb3VwX3RibFt0c2wyNzcxXSwNCisJCQkuZHJpdmVyX21vZHVsZSA9IFRISVNfTU9E VUxFLA0KKwl9LA0KKwlbdHNsMjU3Ml0gPSB7DQorCQkJLmF0dHJzID0gJnRzbDJYN1hfZGV2X2F0 dHJfZ3JvdXBfdGJsW3RzbDI1NzJdLA0KKwkJCS5ldmVudF9hdHRycyA9ICZ0c2wyWDdYX2V2ZW50 X2F0dHJfZ3JvdXBfdGJsW3RzbDI1NzJdLA0KKwkJCS5kcml2ZXJfbW9kdWxlID0gVEhJU19NT0RV TEUsDQorCX0sDQorCVt0c2wyNjcyXSA9IHsNCisJCQkuYXR0cnMgPSAmdHNsMlg3WF9kZXZfYXR0 cl9ncm91cF90YmxbdHNsMjY3Ml0sDQorCQkJLmV2ZW50X2F0dHJzID0gJnRzbDJYN1hfZXZlbnRf YXR0cl9ncm91cF90YmxbdHNsMjY3Ml0sDQorCQkJLmRyaXZlcl9tb2R1bGUgPSBUSElTX01PRFVM RSwNCisJfSwNCisJW3RtZDI2NzJdID0gew0KKwkJCS5hdHRycyA9ICZ0c2wyWDdYX2Rldl9hdHRy X2dyb3VwX3RibFt0c2wyNjcyXSwNCisJCQkuZXZlbnRfYXR0cnMgPSAmdHNsMlg3WF9ldmVudF9h dHRyX2dyb3VwX3RibFt0c2wyNjcyXSwNCisJCQkuZHJpdmVyX21vZHVsZSA9IFRISVNfTU9EVUxF LA0KKwl9LA0KKwlbdHNsMjc3Ml0gPSB7DQorCQkJLmF0dHJzID0gJnRzbDJYN1hfZGV2X2F0dHJf Z3JvdXBfdGJsW3RzbDI3NzJdLA0KKwkJCS5ldmVudF9hdHRycyA9ICZ0c2wyWDdYX2V2ZW50X2F0 dHJfZ3JvdXBfdGJsW3RzbDI3NzJdLA0KKwkJCS5kcml2ZXJfbW9kdWxlID0gVEhJU19NT0RVTEUs DQorCX0sDQorCVt0bWQyNzcyXSA9IHsNCisJCQkuYXR0cnMgPSAmdHNsMlg3WF9kZXZfYXR0cl9n cm91cF90YmxbdHNsMjc3Ml0sDQorCQkJLmV2ZW50X2F0dHJzID0gJnRzbDJYN1hfZXZlbnRfYXR0 cl9ncm91cF90YmxbdHNsMjc3Ml0sDQorCQkJLmRyaXZlcl9tb2R1bGUgPSBUSElTX01PRFVMRSwN CisJfSwNCisNCit9Ow0KKw0KKy8qDQorICogUnVuLXRpbWUgaW50ZXJydXB0IGhhbmRsZXIgLSBk ZXBlbmRpbmcgb24gd2hldGhlciB0aGUgZGV2aWNlIGlzIGluIGFtYmllbnQNCisgKiBsaWdodCBz ZW5zaW5nIGludGVycnVwdCBtb2RlLCB0aGlzIGhhbmRsZXIgY2FuIHF1ZXVlIHVwDQorICogYSB0 aHJlYWQsIHRvIGhhbmRsZSB2YWxpZCBpbnRlcnJ1cHRzLg0KKyAqLw0KK3N0YXRpYyBpcnFyZXR1 cm5fdCB0c2wyeDd4X2V2ZW50X2hhbmRsZXIoaW50IGlycSwgdm9pZCAqcHJpdmF0ZSkNCit7DQor CXN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYgPSBwcml2YXRlOw0KKwlzdHJ1Y3QgdHNsMlg3WF9j aGlwICpjaGlwID0gaWlvX3ByaXYoaW5kaW9fZGV2KTsNCisJczY0IHRpbWVzdGFtcCA9IGlpb19n ZXRfdGltZV9ucygpOw0KKwlpbnQgcmV0Ow0KKwlpbnQgdmFsdWU7DQorDQorCXZhbHVlID0gaTJj X3NtYnVzX3JlYWRfYnl0ZV9kYXRhKGNoaXAtPmNsaWVudCwNCisJCVRTTDJYN1hfQ01EX1JFRyB8 IFRTTDJYN1hfU1RBVFVTKTsNCisNCisJLyogV2hhdCB0eXBlIG9mIGludGVycnVwdCBkbyB3ZSBu ZWVkIHRvIHByb2Nlc3MgKi8NCisJaWYgKHZhbHVlICYgVFNMMlg3WF9TVEFfUFJYX0lOVFIpIHsN CisJCXRzbDJ4N3hfcHJveF9wb2xsKGluZGlvX2Rldik7DQorCQlpaW9fcHVzaF9ldmVudChpbmRp b19kZXYsDQorCQkJICAgICAgIElJT19VTk1PRF9FVkVOVF9DT0RFKElJT19QUk9YSU1JVFksDQor CQkJCQkJICAgIDAsDQorCQkJCQkJICAgIElJT19FVl9UWVBFX1RIUkVTSCwNCisJCQkJCQkgICAg SUlPX0VWX0RJUl9FSVRIRVIpLA0KKwkJCQkJCSAgICB0aW1lc3RhbXApOw0KKwl9DQorDQorCWlm ICh2YWx1ZSAmIFRTTDJYN1hfU1RBX0FMU19JTlRSKSB7DQorCQl0c2wyeDd4X2dldF9sdXgoaW5k aW9fZGV2KTsNCisJCWlpb19wdXNoX2V2ZW50KGluZGlvX2RldiwNCisJCSAgICAgICBJSU9fVU5N T0RfRVZFTlRfQ09ERShJSU9fTElHSFQsDQorCQkJCQkgICAgMCwNCisJCQkJCSAgICBJSU9fRVZf VFlQRV9USFJFU0gsDQorCQkJCQkgICAgSUlPX0VWX0RJUl9FSVRIRVIpLA0KKwkJCQkJICAgIHRp bWVzdGFtcCk7DQorCX0NCisJLyogQ2xlYXIgaW50ZXJydXB0IG5vdyB0aGF0IHdlIGhhdmUgdGhl IHN0YXR1cyAqLw0KKwlyZXQgPSBpMmNfc21idXNfd3JpdGVfYnl0ZShjaGlwLT5jbGllbnQsDQor CQlUU0wyWDdYX0NNRF9SRUcgfCBUU0wyWDdYX0NNRF9TUExfRk4gfA0KKwkJVFNMMlg3WF9DTURf UFJPWEFMU19JTlRDTFIpOw0KKwlpZiAocmV0IDwgMCkNCisJCWRldl9lcnIoJmNoaXAtPmNsaWVu dC0+ZGV2LA0KKwkJIkZhaWxlZCB0byBjbGVhciBpcnEgZnJvbSBldmVudCBoYW5kbGVyLiBlcnIg PSAlZFxuIiwgcmV0KTsNCisNCisJcmV0dXJuIElSUV9IQU5ETEVEOw0KK30NCisNCisvKg0KKyAq IENsaWVudCBwcm9iZSBmdW5jdGlvbi4NCisgKi8NCitzdGF0aWMgaW50IF9fZGV2aW5pdCB0c2wy eDd4X3Byb2JlKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnRwLA0KKwljb25zdCBzdHJ1Y3QgaTJj X2RldmljZV9pZCAqaWQpDQorew0KKwlpbnQgaSwgcmV0Ow0KKwl1bnNpZ25lZCBjaGFyIGJ1ZltU U0wyWDdYX01BWF9ERVZJQ0VfUkVHU107DQorCXN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYgPQ0K KwkJCWlpb19hbGxvY2F0ZV9kZXZpY2Uoc2l6ZW9mKHN0cnVjdCB0c2wyWDdYX2NoaXApKTsNCisJ c3RydWN0IHRzbDJYN1hfY2hpcAkqY2hpcCA9IGlpb19wcml2KGluZGlvX2Rldik7DQorDQorCWlm IChpbmRpb19kZXYgPT0gTlVMTCkgew0KKwkJcmV0ID0gLUVOT01FTTsNCisJCWRldl9lcnIoJmNs aWVudHAtPmRldiwgImlpbyBhbGxvY2F0aW9uIGZhaWxlZFxuIik7DQorCQlnb3RvIGZhaWwxOw0K Kwl9DQorDQorCWNoaXAgPSBpaW9fcHJpdihpbmRpb19kZXYpOw0KKwljaGlwLT5jbGllbnQgPSBj bGllbnRwOw0KKwlpMmNfc2V0X2NsaWVudGRhdGEoY2xpZW50cCwgaW5kaW9fZGV2KTsNCisNCisJ bXV0ZXhfaW5pdCgmY2hpcC0+YWxzX211dGV4KTsNCisJbXV0ZXhfaW5pdCgmY2hpcC0+cHJveF9t dXRleCk7DQorDQorCWNoaXAtPnRzbDJ4N3hfY2hpcF9zdGF0dXMgPSBUU0wyWDdYX0NISVBfVU5L Tk9XTjsNCisNCisJY2hpcC0+cGRhdGEgPSBjbGllbnRwLT5kZXYucGxhdGZvcm1fZGF0YTsNCisJ aWYgKGNoaXAtPnBkYXRhICYmIGNoaXAtPnBkYXRhLT5pbml0KQ0KKwkJCWNoaXAtPnBkYXRhLT5p bml0KGNsaWVudHApOw0KKw0KKwlmb3IgKGkgPSAwOyBpIDwgVFNMMlg3WF9NQVhfREVWSUNFX1JF R1M7IGkrKykgew0KKwkJcmV0ID0gaTJjX3NtYnVzX3dyaXRlX2J5dGUoY2xpZW50cCwNCisJCQkJ KFRTTDJYN1hfQ01EX1JFRyB8IChUU0wyWDdYX0NOVFJMICsgaSkpKTsNCisJCWlmIChyZXQgPCAw KSB7DQorCQkJZGV2X2VycigmY2xpZW50cC0+ZGV2LCAiaTJjX3NtYnVzX3dyaXRlX2J5dGVzKCkg dG8gY21kICINCisJCQkicmVnIGZhaWxlZCBpbiB0c2wyeDd4X3Byb2JlKCksIGVyciA9ICVkXG4i LCByZXQpOw0KKwkJCWdvdG8gZmFpbDE7DQorCQl9DQorCQlyZXQgPSBpMmNfc21idXNfcmVhZF9i eXRlKGNsaWVudHApOw0KKwkJaWYgKHJldCA8IDApIHsNCisJCQlkZXZfZXJyKCZjbGllbnRwLT5k ZXYsICJpMmNfc21idXNfcmVhZF9ieXRlIGZyb20gIg0KKwkJCSJyZWcgZmFpbGVkIGluIHRzbDJ4 N3hfcHJvYmUoKSwgZXJyID0gJWRcbiIsIHJldCk7DQorDQorCQkJZ290byBmYWlsMTsNCisJCX0N CisJCWJ1ZltpXSA9IHJldDsNCisJfQ0KKw0KKwlpZiAoKCF0c2wyeDd4X2RldmljZV9pZChidWYs IGlkLT5kcml2ZXJfZGF0YSkpIHx8DQorCQkJKHRzbDJ4N3hfZGV2aWNlX2lkKGJ1ZiwgaWQtPmRy aXZlcl9kYXRhKSA9PSAtRUlOVkFMKSkgew0KKwkJZGV2X2luZm8oJmNoaXAtPmNsaWVudC0+ZGV2 LCAiaTJjIGRldmljZSBmb3VuZCBidXQgZG9lcyBub3QgbWF0Y2ggIg0KKwkJCSJleHBlY3RlZCBp ZCBpbiB0c2wyeDd4X3Byb2JlKClcbiIpOw0KKwkJZ290byBmYWlsMTsNCisJfQ0KKw0KKwljaGlw LT5pZCA9IGlkLT5kcml2ZXJfZGF0YTsNCisNCisJcmV0ID0gaTJjX3NtYnVzX3dyaXRlX2J5dGUo Y2xpZW50cCwgKFRTTDJYN1hfQ01EX1JFRyB8IFRTTDJYN1hfQ05UUkwpKTsNCisJaWYgKHJldCA8 IDApIHsNCisJCWRldl9lcnIoJmNsaWVudHAtPmRldiwgImkyY19zbWJ1c193cml0ZV9ieXRlKCkg dG8gY21kIHJlZyAiDQorCQkJImZhaWxlZCBpbiB0c2wyeDd4X3Byb2JlKCksIGVyciA9ICVkXG4i LCByZXQpOw0KKwkJZ290byBmYWlsMTsNCisJfQ0KKw0KKwlpbmRpb19kZXYtPmluZm8gPSAmdHNs Mlg3WF9pbmZvW2lkLT5kcml2ZXJfZGF0YV07DQorCWluZGlvX2Rldi0+ZGV2LnBhcmVudCA9ICZj bGllbnRwLT5kZXY7DQorCWluZGlvX2Rldi0+bW9kZXMgPSBJTkRJT19ESVJFQ1RfTU9ERTsNCisJ aW5kaW9fZGV2LT5uYW1lID0gY2hpcC0+Y2xpZW50LT5uYW1lOw0KKwlpbmRpb19kZXYtPmNoYW5u ZWxzID0gdHNsMlg3WF9jaGFubmVsczsNCisJaW5kaW9fZGV2LT5udW1fY2hhbm5lbHMgPSBBUlJB WV9TSVpFKHRzbDJYN1hfY2hhbm5lbHMpOw0KKw0KKwlyZXQgPSBpaW9fZGV2aWNlX3JlZ2lzdGVy KGluZGlvX2Rldik7DQorCWlmIChyZXQpIHsNCisJCWRldl9lcnIoJmNsaWVudHAtPmRldiwgImlp byByZWdpc3RyYXRpb24gZmFpbGVkXG4iKTsNCisJCWdvdG8gZmFpbDI7DQorCX0NCisNCisJaWYg KGNsaWVudHAtPmlycSkgew0KKwkJcmV0ID0gcmVxdWVzdF90aHJlYWRlZF9pcnEoY2xpZW50cC0+ aXJxLA0KKwkJCQkJICAgTlVMTCwNCisJCQkJCSAgICZ0c2wyeDd4X2V2ZW50X2hhbmRsZXIsDQor CQkJCQkgICBJUlFGX1RSSUdHRVJfUklTSU5HIHwgSVJRRl9PTkVTSE9ULA0KKwkJCQkJICAgIlRT TDJYN1hfZXZlbnQiLA0KKwkJCQkJICAgaW5kaW9fZGV2KTsNCisJCWlmIChyZXQpDQorCQkJZGV2 X2VycigmY2xpZW50cC0+ZGV2LCAiaXJxIHJlcXVlc3QgZmFpbGVkIik7DQorCX0NCisNCisJLyog TG9hZCB1cCB0aGUgZGVmYXVsdHMgKi8NCisJdHNsMng3eF9kZWZhdWx0cyhjaGlwKTsNCisNCisJ LyogTWFrZSBzdXJlIHRoZSBjaGlwIGlzIG9uICovDQorCXRzbDJ4N3hfY2hpcF9vbihpbmRpb19k ZXYpOw0KKw0KKwlkZXZfaW5mbygmY2xpZW50cC0+ZGV2LCAiJXMgTGlnaHQgc2Vuc29yIGZvdW5k LlxuIiwgaWQtPm5hbWUpOw0KKw0KKwlyZXR1cm4gMDsNCisNCitmYWlsMToNCisJaWYgKGNoaXAt PnBkYXRhICYmIGNoaXAtPnBkYXRhLT50ZWFyZG93bikNCisJCWNoaXAtPnBkYXRhLT50ZWFyZG93 bihjbGllbnRwKTsNCisJaWlvX2ZyZWVfZGV2aWNlKGluZGlvX2Rldik7DQorDQorZmFpbDI6DQor CXJldHVybiByZXQ7DQorDQorfQ0KKw0KKw0KK3N0YXRpYyBpbnQgdHNsMng3eF9zdXNwZW5kKHN0 cnVjdCBkZXZpY2UgKmRldikNCit7DQorCXN0cnVjdCBpaW9fZGV2ICpkZXZfaW5mbyA9IGRldl9n ZXRfZHJ2ZGF0YShkZXYpOw0KKwlzdHJ1Y3QgdHNsMlg3WF9jaGlwICpjaGlwID0gaWlvX3ByaXYo ZGV2X2luZm8pOw0KKw0KKwlpbnQgcmV0ID0gMDsNCisNCisJLyogQmxvY2tzIGlmIHdvcmsgaXMg YWN0aXZlICovDQorCWNhbmNlbF93b3JrX3N5bmMoJmNoaXAtPndvcmtfdGhyZXNoKTsNCisNCisJ aWYgKGNoaXAtPnRzbDJ4N3hfY2hpcF9zdGF0dXMgPT0gVFNMMlg3WF9DSElQX1dPUktJTkcpIHsN CisJCXJldCA9IHRzbDJ4N3hfY2hpcF9vZmYoZGV2X2luZm8pOw0KKwkJY2hpcC0+dHNsMng3eF9j aGlwX3N0YXR1cyA9IFRTTDJYN1hfQ0hJUF9TVVNQRU5ERUQ7DQorCX0NCisNCisJaWYgKGNoaXAt PnBkYXRhICYmIGNoaXAtPnBkYXRhLT5wbGF0Zm9ybV9wb3dlcikgew0KKwkJcG1fbWVzc2FnZV90 IHBtbSA9IHtQTV9FVkVOVF9TVVNQRU5EfTsNCisJCWNoaXAtPnBkYXRhLT5wbGF0Zm9ybV9wb3dl cihkZXYsIHBtbSk7DQorCX0NCisNCisJcmV0dXJuIHJldDsNCit9DQorDQorc3RhdGljIGludCB0 c2wyeDd4X3Jlc3VtZShzdHJ1Y3QgZGV2aWNlICpkZXYpDQorew0KKwlzdHJ1Y3QgaWlvX2RldiAq ZGV2X2luZm8gPSBkZXZfZ2V0X2RydmRhdGEoZGV2KTsNCisJc3RydWN0IHRzbDJYN1hfY2hpcCAq Y2hpcCA9IGlpb19wcml2KGRldl9pbmZvKTsNCisJaW50IHJldCA9IDA7DQorDQorCWlmIChjaGlw LT5wZGF0YSAmJiBjaGlwLT5wZGF0YS0+cGxhdGZvcm1fcG93ZXIpIHsNCisJCXBtX21lc3NhZ2Vf dCBwbW0gPSB7UE1fRVZFTlRfUkVTVU1FfTsNCisJCWNoaXAtPnBkYXRhLT5wbGF0Zm9ybV9wb3dl cihkZXYsIHBtbSk7DQorCX0NCisNCisJaWYgKGNoaXAtPnRzbDJ4N3hfY2hpcF9zdGF0dXMgPT0g VFNMMlg3WF9DSElQX1NVU1BFTkRFRCkNCisJCXJldCA9IHRzbDJ4N3hfY2hpcF9vbihkZXZfaW5m byk7DQorDQorCXJldHVybiByZXQ7DQorfQ0KKw0KK3N0YXRpYyBpbnQgX19kZXZleGl0IHRzbDJ4 N3hfcmVtb3ZlKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQpDQorew0KKwlzdHJ1Y3QgaWlvX2Rl diAqaW5kaW9fZGV2ID0gaTJjX2dldF9jbGllbnRkYXRhKGNsaWVudCk7DQorCXN0cnVjdCB0c2wy WDdYX2NoaXAgKmNoaXAgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50KTsNCisNCisJdHNsMng3 eF9jaGlwX29mZihpbmRpb19kZXYpOw0KKw0KKwlpZiAoY2xpZW50LT5pcnEpDQorCQlmcmVlX2ly cShjbGllbnQtPmlycSwgY2hpcC0+Y2xpZW50LT5uYW1lKTsNCisNCisJZmx1c2hfc2NoZWR1bGVk X3dvcmsoKTsNCisNCisJaWlvX2RldmljZV91bnJlZ2lzdGVyKGNoaXAtPmlpb19kZXYpOw0KKwlr ZnJlZShjaGlwKTsNCisNCisJaWYgKGNoaXAtPnBkYXRhICYmIGNoaXAtPnBkYXRhLT50ZWFyZG93 bikNCisJCWNoaXAtPnBkYXRhLT50ZWFyZG93bihjbGllbnQpOw0KKw0KKwlyZXR1cm4gMDsNCit9 DQorDQorc3RhdGljIHN0cnVjdCBpMmNfZGV2aWNlX2lkIHRzbDJ4N3hfaWR0YWJsZVtdID0gew0K Kwl7ICJ0c2wyNTcxIiwgdHNsMjU3MSB9LA0KKwl7ICJ0c2wyNjcxIiwgdHNsMjY3MSB9LA0KKwl7 ICJ0bWQyNjcxIiwgdG1kMjY3MSB9LA0KKwl7ICJ0c2wyNzcxIiwgdHNsMjc3MSB9LA0KKwl7ICJ0 bWQyNzcxIiwgdG1kMjc3MSB9LA0KKwl7ICJ0c2wyNTcyIiwgdHNsMjU3MiB9LA0KKwl7ICJ0c2wy NjcyIiwgdHNsMjY3MiB9LA0KKwl7ICJ0bWQyNjcyIiwgdG1kMjY3MiB9LA0KKwl7ICJ0c2wyNzcy IiwgdHNsMjc3MiB9LA0KKwl7ICJ0bWQyNzcyIiwgdG1kMjc3MiB9LA0KKwl7fQ0KK307DQorDQor TU9EVUxFX0RFVklDRV9UQUJMRShpMmMsIHRzbDJ4N3hfaWR0YWJsZSk7DQorDQorc3RhdGljIGNv bnN0IHN0cnVjdCBkZXZfcG1fb3BzIHRzbDJ4N3hfcG1fb3BzID0gew0KKwkuc3VzcGVuZCA9IHRz bDJ4N3hfc3VzcGVuZCwNCisJLnJlc3VtZSAgPSB0c2wyeDd4X3Jlc3VtZSwNCit9Ow0KKw0KKy8q IERyaXZlciBkZWZpbml0aW9uICovDQorc3RhdGljIHN0cnVjdCBpMmNfZHJpdmVyIHRzbDJ4N3hf ZHJpdmVyID0gew0KKwkuZHJpdmVyID0gew0KKwkJLm5hbWUgPSAidHNsMlg3WCIsDQorCQkucG0g PSAmdHNsMng3eF9wbV9vcHMsDQorDQorCX0sDQorCS5pZF90YWJsZSA9IHRzbDJ4N3hfaWR0YWJs ZSwNCisJLnByb2JlID0gdHNsMng3eF9wcm9iZSwNCisJLnJlbW92ZSA9IF9fZGV2ZXhpdF9wKHRz bDJ4N3hfcmVtb3ZlKSwNCit9Ow0KKw0KK3N0YXRpYyBpbnQgX19pbml0IHRzbDJ4N3hfaW5pdCh2 b2lkKQ0KK3sNCisJcmV0dXJuIGkyY19hZGRfZHJpdmVyKCZ0c2wyeDd4X2RyaXZlcik7DQorfQ0K Kw0KK3N0YXRpYyB2b2lkIF9fZXhpdCB0c2wyeDd4X2V4aXQodm9pZCkNCit7DQorCWkyY19kZWxf ZHJpdmVyKCZ0c2wyeDd4X2RyaXZlcik7DQorfQ0KKw0KK21vZHVsZV9pbml0KHRzbDJ4N3hfaW5p dCk7DQorbW9kdWxlX2V4aXQodHNsMng3eF9leGl0KTsNCisNCitNT0RVTEVfQVVUSE9SKCJKLiBB dWd1c3QgQnJlbm5lcjxqYnJlbm5lckB0YW9zaW5jLmNvbT4iKTsNCitNT0RVTEVfREVTQ1JJUFRJ T04oIlRBT1MgdHNsMlg3WCBhbWJpZW50IGxpZ2h0IHNlbnNvciBkcml2ZXIiKTsNCitNT0RVTEVf TElDRU5TRSgiR1BMIik7DQpkaWZmIC0tZ2l0IGEvZHJpdmVycy9zdGFnaW5nL2lpby9saWdodC90 c2wyeDd4X2NvcmUuaCBiL2RyaXZlcnMvc3RhZ2luZy9paW8vbGlnaHQvdHNsMng3eF9jb3JlLmgN Cm5ldyBmaWxlIG1vZGUgMTAwNjQ0DQppbmRleCAwMDAwMDAwLi45YTY0NDEyDQotLS0gL2Rldi9u dWxsDQorKysgYi9kcml2ZXJzL3N0YWdpbmcvaWlvL2xpZ2h0L3RzbDJ4N3hfY29yZS5oDQpAQCAt MCwwICsxLDEzOCBAQA0KKy8qDQorICogRGV2aWNlIGRyaXZlciBmb3IgbW9uaXRvcmluZyBhbWJp ZW50IGxpZ2h0IGludGVuc2l0eSAobHV4KQ0KKyAqIGFuZCBwcm94aW1pdHkgKHByb3gpIHdpdGhp biB0aGUgVEFPUyBUU0wyWDdYIGZhbWlseSBvZiBkZXZpY2VzLg0KKyAqDQorICogQ29weXJpZ2h0 IChjKSAyMDEyLCBUQU9TIENvcnBvcmF0aW9uLg0KKyAqDQorICogVGhpcyBwcm9ncmFtIGlzIGZy ZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnkNCisgKiBp dCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1 Ymxpc2hlZCBieQ0KKyAqIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJz aW9uIDIgb2YgdGhlIExpY2Vuc2UsIG9yDQorICogKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIg dmVyc2lvbi4NCisgKg0KKyAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9w ZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLCBidXQgV0lUSE9VVA0KKyAqIEFOWSBXQVJSQU5UWTsg d2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mIE1FUkNIQU5UQUJJTElUWSBvcg0K KyAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlUgR2VuZXJh bCBQdWJsaWMgTGljZW5zZSBmb3INCisgKiBtb3JlIGRldGFpbHMuDQorICoNCisgKiBZb3Ugc2hv dWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5z ZSBhbG9uZw0KKyAqIHdpdGggdGhpcyBwcm9ncmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVl IFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4sDQorICogNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0 aCBGbG9vciwgQm9zdG9uLCBNQQkwMjExMC0xMzAxLCBVU0EuDQorICovDQorDQorI2lmbmRlZiBf X1RTTDJYN1hfSA0KKyNkZWZpbmUgX19UU0wyWDdYX0gNCisjaW5jbHVkZSA8bGludXgvcG0uaD4N CisNCisjaW5jbHVkZSAiLi4vaWlvLmgiDQorDQorLyogVEFPUyBSZWdpc3RlciBkZWZpbml0aW9u cyAtIG5vdGU6DQorICogZGVwZW5kaW5nIG9uIGRldmljZSwgc29tZSBvZiB0aGVzZSByZWdpc3Rl ciBhcmUgbm90IHVzZWQgYW5kIHRoZQ0KKyAqIHJlZ2lzdGVyIGFkZHJlc3MgaXMgYmVuaWduLg0K KyAqLw0KKy8qIDJYN1ggcmVnaXN0ZXIgb2Zmc2V0cyAqLw0KKyNkZWZpbmUgVFNMMlg3WF9NQVhf REVWSUNFX1JFR1MgMzINCisjZGVmaW5lIFRTTDJYN1hfUkVHX01BWCAgICAgICAgIDE2DQorDQor LyogRGV2aWNlIFJlZ2lzdGVycyBhbmQgTWFza3MgKi8NCisjZGVmaW5lIFRTTDJYN1hfQ05UUkwg ICAgICAgICAgICAgICAgICAweDAwDQorI2RlZmluZSBUU0wyWDdYX0FMU19USU1FICAgICAgICAg ICAgICAgMFgwMQ0KKyNkZWZpbmUgVFNMMlg3WF9QUlhfVElNRSAgICAgICAgICAgICAgIDB4MDIN CisjZGVmaW5lIFRTTDJYN1hfV0FJVF9USU1FICAgICAgICAgICAgICAweDAzDQorI2RlZmluZSBU U0wyWDdYX0FMU19NSU5USFJFU0hMTyAgICAgICAgMFgwNA0KKyNkZWZpbmUgVFNMMlg3WF9BTFNf TUlOVEhSRVNISEkgICAgICAgIDBYMDUNCisjZGVmaW5lIFRTTDJYN1hfQUxTX01BWFRIUkVTSExP ICAgICAgICAwWDA2DQorI2RlZmluZSBUU0wyWDdYX0FMU19NQVhUSFJFU0hISSAgICAgICAgMFgw Nw0KKyNkZWZpbmUgVFNMMlg3WF9QUlhfTUlOVEhSRVNITE8gICAgICAgIDBYMDgNCisjZGVmaW5l IFRTTDJYN1hfUFJYX01JTlRIUkVTSEhJICAgICAgICAwWDA5DQorI2RlZmluZSBUU0wyWDdYX1BS WF9NQVhUSFJFU0hMTyAgICAgICAgMFgwQQ0KKyNkZWZpbmUgVFNMMlg3WF9QUlhfTUFYVEhSRVNI SEkgICAgICAgIDBYMEINCisjZGVmaW5lIFRTTDJYN1hfUEVSU0lTVEVOQ0UgICAgICAgICAgICAw eDBDDQorI2RlZmluZSBUU0wyWDdYX1BSWF9DT05GSUcgICAgICAgICAgICAgMHgwRA0KKyNkZWZp bmUgVFNMMlg3WF9QUlhfQ09VTlQgICAgICAgICAgICAgIDB4MEUNCisjZGVmaW5lIFRTTDJYN1hf R0FJTiAgICAgICAgICAgICAgICAgICAweDBGDQorI2RlZmluZSBUU0wyWDdYX05PVFVTRUQgICAg ICAgICAgICAgICAgMHgxMA0KKyNkZWZpbmUgVFNMMlg3WF9SRVZJRCAgICAgICAgICAgICAgICAg IDB4MTENCisjZGVmaW5lIFRTTDJYN1hfQ0hJUElEICAgICAgICAgICAgICAgICAweDEyDQorI2Rl ZmluZSBUU0wyWDdYX1NUQVRVUyAgICAgICAgICAgICAgICAgMHgxMw0KKyNkZWZpbmUgVFNMMlg3 WF9BTFNfQ0hBTjBMTyAgICAgICAgICAgIDB4MTQNCisjZGVmaW5lIFRTTDJYN1hfQUxTX0NIQU4w SEkgICAgICAgICAgICAweDE1DQorI2RlZmluZSBUU0wyWDdYX0FMU19DSEFOMUxPICAgICAgICAg ICAgMHgxNg0KKyNkZWZpbmUgVFNMMlg3WF9BTFNfQ0hBTjFISSAgICAgICAgICAgIDB4MTcNCisj ZGVmaW5lIFRTTDJYN1hfUFJYX0xPICAgICAgICAgICAgICAgICAweDE4DQorI2RlZmluZSBUU0wy WDdYX1BSWF9ISSAgICAgICAgICAgICAgICAgMHgxOQ0KKw0KKy8qIHRzbDJYN1ggY21kIHJlZyBt YXNrcyAqLw0KKyNkZWZpbmUgVFNMMlg3WF9DTURfUkVHICAgICAgICAgICAgICAgIDB4ODANCisj ZGVmaW5lIFRTTDJYN1hfQ01EX1NQTF9GTiAgICAgICAgICAgICAweDYwDQorDQorI2RlZmluZSBU U0wyWDdYX0NNRF9QUk9YX0lOVF9DTFIgICAgICAgMFgwNQ0KKyNkZWZpbmUgVFNMMlg3WF9DTURf QUxTX0lOVF9DTFIgICAgICAgIDB4MDYNCisjZGVmaW5lIENNRF9QUk9YQUxTX0lOVF9DTFIgICAg ICAgICAgICAwWDA3DQorDQorLyogdHNsMlg3WCBjbnRybCByZWcgbWFza3MgKi8NCisjZGVmaW5l IFRTTDJYN1hfQ05UTF9BRENfRU5CTCAgICAgICAgICAweDAyDQorI2RlZmluZSBUU0wyWDdYX0NO VExfUFdSX09OICAgICAgICAgICAgMHgwMQ0KKw0KKy8qIHRzbDJYN1ggc3RhdHVzIHJlZyBtYXNr cyAqLw0KKyNkZWZpbmUgVFNMMlg3WF9TVEFfQURDX1ZBTElEICAgICAgICAgIDB4MDENCisjZGVm aW5lIFRTTDJYN1hfU1RBX1BSWF9WQUxJRCAgICAgICAgICAweDAyDQorI2RlZmluZSBUU0wyWDdY X1NUQV9BRENfUFJYX1ZBTElEICAgICAgMHgwMw0KKyNkZWZpbmUgVFNMMlg3WF9TVEFfQUxTX0lO VFIgICAgICAgICAgIDB4MTANCisjZGVmaW5lIFRTTDJYN1hfU1RBX0FEQ19JTlRSICAgICAgICAg ICAweDEwDQorI2RlZmluZSBUU0wyWDdYX1NUQV9QUlhfSU5UUiAgICAgICAgICAgMHgyMA0KKw0K KyNkZWZpbmUgVFNMMlg3WF9TVEFfQURDX0lOVFIgICAgICAgICAgIDB4MTANCisNCisvKiB0c2wy WDdYIGNudHJsIHJlZyBtYXNrcyAqLw0KKyNkZWZpbmUgQ05UTF9SRUdfQ0xFQVIgICAgICAgICAg ICAgICAgIDB4MDANCisjZGVmaW5lIENOVExfUFJPWF9JTlRfRU5CTCAgICAgICAgICAgICAwWDIw DQorI2RlZmluZSBDTlRMX0FMU19JTlRfRU5CTCAgICAgICAgICAgICAgMFgxMA0KKyNkZWZpbmUg VFNMMlg3WF9DTlRMX1dBSVRfVE1SX0VOQkwgICAgIDBYMDgNCisjZGVmaW5lIENOVExfUFJPWF9E RVRfRU5CTCAgICAgICAgICAgICAwWDA0DQorI2RlZmluZSBDTlRMX0FEQ19FTkJMICAgICAgICAg ICAgICAgICAgMHgwMg0KKyNkZWZpbmUgVFNMMlg3WF9DTlRMX1BXUk9OICAgICAgICAgICAgIDB4 MDENCisjZGVmaW5lIENOVExfQUxTUE9OX0VOQkwgICAgICAgICAgICAgICAweDAzDQorI2RlZmlu ZSBDTlRMX0lOVEFMU1BPTl9FTkJMICAgICAgICAgICAgMHgxMw0KKyNkZWZpbmUgQ05UTF9QUk9Y UE9OX0VOQkwgICAgICAgICAgICAgIDB4MEYNCisjZGVmaW5lIENOVExfSU5UUFJPWFBPTl9FTkJM ICAgICAgICAgICAweDJGDQorI2RlZmluZSBUU0wyWDdYX0NNRF9QUk9YQUxTX0lOVENMUiAgICAg MFgwNw0KKw0KKy8qUHJveCBkaW9kZSB0byB1c2UgKi8NCisjZGVmaW5lIERJT0RFMCAgICAgICAg ICAgICAgICAgICAgICAgICAweDEwDQorI2RlZmluZSBESU9ERTEgICAgICAgICAgICAgICAgICAg ICAgICAgMHgyMA0KKyNkZWZpbmUgRElPREVfQk9USCAgICAgICAgICAgICAgICAgICAgIDB4MzAN CisNCisvKiBMRUQgUG93ZXIgKi8NCisjZGVmaW5lIG1BMTAwICAgICAgICAgICAgICAgICAgICAg ICAgICAweDAwDQorI2RlZmluZSBtQTUwICAgICAgICAgICAgICAgICAgICAgICAgICAgMHg0MA0K KyNkZWZpbmUgbUEyNSAgICAgICAgICAgICAgICAgICAgICAgICAgIDB4ODANCisjZGVmaW5lIG1B MTMgICAgICAgICAgICAgICAgICAgICAgICAgICAweEQwDQorDQorLyogTWF4IG51bWJlciBvZiBz ZWdtZW50cyBhbGxvd2FibGUgaW4gTFVYIHRhYmxlICovDQorI2RlZmluZSBNQVhfVEFCTEVfU0la RQkJOQ0KKyNkZWZpbmUgTUFYX0RFRkFVTFRfVEFCTEVfQllURVMgKHNpemVvZihpbnQpICogTUFY X1RBQkxFX1NJWkUpDQorDQorc3RydWN0IHRzbDJ4N3hfbHV4IHsNCisJdW5zaWduZWQgaW50IHJh dGlvOw0KKwl1bnNpZ25lZCBpbnQgY2gwOw0KKwl1bnNpZ25lZCBpbnQgY2gxOw0KK307DQorDQor DQorLyogc3RydWN0IHRzbDJ4N3hfcGxhdGZvcm1fZGF0YSAtIEFzc3VtZSBhbGwgdmFyaWVudHMg d2lsbCBoYXZlIHRoaXMgKi8NCitzdHJ1Y3QgdHNsMlg3WF9wbGF0Zm9ybV9kYXRhIHsNCisJaW50 ICgqcGxhdGZvcm1fcG93ZXIpKHN0cnVjdCBkZXZpY2UgKmRldiwgcG1fbWVzc2FnZV90KTsNCisJ LyogVGhlIGZvbGxvd2luZyBjYWxsYmFjayBnZXRzIGNhbGxlZCB3aGVuIHRoZSBUU0wyNzcyIGlz IHBvd2VyZWQgb24gKi8NCisJaW50ICgqcG93ZXJfb24pICAgICAgKHN0cnVjdCBpaW9fZGV2ICpp bmRpb19kZXYpOw0KKwkvKiBUaGUgZm9sbG93aW5nIGNhbGxiYWNrIGdldHMgY2FsbGVkIHdoZW4g dGhlIFRTTDI3NzIgaXMgcG93ZXJlZCBvZmYgKi8NCisJaW50ICgqcG93ZXJfb2ZmKSAgICAgKHN0 cnVjdCBpMmNfY2xpZW50ICpkZXYpOw0KKwkvKiBUaGUgZm9sbG93aW5nIGNhbGxiYWNrIGdldHMg Y2FsbGVkIHdoZW4gdGhlIGRyaXZlciBpcyBhZGRlZCAqLw0KKwlpbnQgKCppbml0KSAgICAgICAg ICAoc3RydWN0IGkyY19jbGllbnQgKmRldik7DQorCS8qIFRoZSBmb2xsb3dpbmcgY2FsbGJhY2sg Z2V0cyBjYWxsZWQgd2hlbiB0aGUgZHJpdmVyIGlzIHJlbW92ZWQgKi8NCisJaW50ICgqdGVhcmRv d24pICAgICAgKHN0cnVjdCBpMmNfY2xpZW50ICpkZXYpOw0KKwkvKiBUaGVzZSBhcmUgdGhlIGRl dmljZSBzcGVjaWZpYyBnbGFzcyBjb2VmZmljZW50cyB1c2VkIHRvDQorCSAqIGNhbGN1bGF0ZSBM dXggKi8NCisJc3RydWN0IHRzbDJ4N3hfbHV4IHBsYXRmb3JtX2x1eF90YWJsZVtNQVhfVEFCTEVf U0laRV07DQorfTsNCisNCisjZW5kaWYgLyogX19UU0wyWDdYX0ggKi8NCi0tDQoxLjcuNC4xDQoN Cg== ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH V1] TAOS tsl2x7x 2012-02-10 19:06 [PATCH V1] TAOS tsl2x7x Jon Brenner @ 2012-02-13 15:19 ` Jonathan Cameron 2012-02-13 15:28 ` Jonathan Cameron 0 siblings, 1 reply; 3+ messages in thread From: Jonathan Cameron @ 2012-02-13 15:19 UTC (permalink / raw) To: Jon Brenner; +Cc: Jonathan Cameron, linux-kernel, linux-iio On 2/10/2012 7:06 PM, Jon Brenner wrote: > TAOS device driver for tsl/tmd 2771 and 2772 device families (inc all variants). > > Signed-off-by: Jon Brenner<jbrenner@taosinc.com> Hi Jon, Good to see another driver from you. Reasonably keen but couple of medium sized issues a) Use iio_chan_spec and callbacks in iio_info structure where possible. Propose additional elements where they make sense (such as your integration time). b) Documentation should be slotted in relevant places in more general files. c) I'm unconvinced the calibration stuff should be in kernel. Thanks, Jonathan > > --- > .../iio/Documentation/sysfs-bus-iio-light-tsl2x7x | 71 + > drivers/staging/iio/light/Kconfig | 11 + > drivers/staging/iio/light/Makefile | 1 + > drivers/staging/iio/light/tsl2x7x_core.c | 2053 ++++++++++++++++++++ > drivers/staging/iio/light/tsl2x7x_core.h | 138 ++ > 5 files changed, 2274 insertions(+), 0 deletions(-) > > diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light-tsl2x7x b/drivers/staging/iio/Documentation/sysfs-bus-iio-light-tsl2x7x > new file mode 100644 > index 0000000..f1bb5f5 > --- /dev/null > +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light-tsl2x7x > @@ -0,0 +1,71 @@ Most of these are fairly general purpose so should be sysfs-bus-iio or sysfs-bus-iio-light. Some are also shared with the tsl2583 doc so maybe move those into the light one. Generally if the last bit (after the channel type) is restricted to the actual device then it wants to be in this file. If it's restricted to the class (light / proximity) then it wants to be in sysfs-bus-iio-light or sysfs-bus-iio-proximity If like proximity_raw or the thresh_value ones then it wants to be in sysfs-bus-iio. Please do fix any cases where this isn't currently the case. Our documentation outside the top level file is far from well written or organized. > +What: /sys/bus/iio/devices/device[n]/lux_table > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property gets/sets the table of coefficients > + used in calculating illuminance in lux. > + > +What: /sys/bus/iio/devices/device[n]/illuminance0_calibrate > +KernelVersion: 2.6.37 > +Contact: linux-iio@vger.kernel.org > +Description: > + This property causes an internal calibration of the als gain trim > + value which is later used in calculating illuminance in lux. > + > +What: /sys/bus/iio/devices/device[n]/illuminance0_thresh_falling_value > +KernelVersion: 3.3-rc1 > +Contact: linux-iio@vger.kernel.org > +Description: > + Low (falling) trigger point for the internal ALS comparison > + function for interrupt generation. This one just needs adding to sysfs-bus-iio. > + > +What: /sys/bus/iio/devices/device[n]/illuminance0_thresh_rising_value > +KernelVersion: 3.3-rc1 > +Contact: linux-iio@vger.kernel.org > +Description: > + high (rising) trigger point for the internal ALS comparison > + function for interrupt generation. > + > +What: /sys/bus/iio/devices/device[n]/illuminance0_both_raw > +KernelVersion: 3.3-rc1 > +Contact: linux-iio@vger.kernel.org > +Description: > + Simultainious ALS channel 1 and channel 2 data represented as > + a 32 bit integer. err. previously the both has referred to the light frequencies covered. Please don't do what you describe here. If you really need to be sure they are pared then you want to use the buffered infrastructure not sysfs. > + > +What: /sys/bus/iio/devices/device[n]/proximity_calibrate > +KernelVersion: 3.3-rc1 > +Contact: linux-iio@vger.kernel.org > +Description: > + Causes an recalculation and adjustment to the > + proximity_thresh_rising_value. > + > +What: /sys/bus/iio/devices/device[n]/proximity_thresh_falling_value > +KernelVersion: 3.3-rc1 > +Contact: linux-iio@vger.kernel.org > +Description: > + Low (falling) trigger point for the internal proximity comparison > + function for interrupt generation. > + Again, standard form so add to sysfs-bus-iio. > +What: /sys/bus/iio/devices/device[n]/proximity_thresh_rising_value > +KernelVersion: 3.3-rc1 > +Contact: linux-iio@vger.kernel.org > +Description: > + high (rising) trigger point for the internal proximity comparison > + function for interrupt generation. > + > +What: /sys/bus/iio/devices/device[n]/proximity_calibscale > +KernelVersion: 3.3-rc1 > +Contact: linux-iio@vger.kernel.org > +Description: > + Hardware or software applied calibration scale factor assumed > + to account for attenuation due to industrial design (glass > + filters or aperture holes). > + All of these are standard so add to sysfs-bus-iio lists for calibscale > +What: /sys/bus/iio/devices/device[n]/proximity_raw > +KernelVersion: 3.3-rc1 > +Contact: linux-iio@vger.kernel.org > +Description: > + State of proximity detection based on the > + proximity_thresh_rising_value. If you wouldn't mind can you lift he proximity documentation out of sysfs-bus-iio-ilght into sysfs-bus-iio then we can take all the standard definitions without adding them yet again. (as a separate patch). I'm still kind of regretting ever introducing multiple sysfs documentatino files. > + > diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig > index e7e9159..29de333 100644 > --- a/drivers/staging/iio/light/Kconfig > +++ b/drivers/staging/iio/light/Kconfig > @@ -31,4 +31,15 @@ config TSL2583 > Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. > Access ALS data via iio, sysfs. > > + This driver can also be built as a module. If so, the module > + will be called tsl2583. errr. This change to a comment about a completely different driver should not be in this patch. > + > +config TSL2x7x > + tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" > + depends on I2C > + help > + Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672, > + tmd2672, tsl2772, tmd2772 devices. > + Provides iio_events and direct access via sysfs. > + > endmenu > diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile > index 3011fbf..ff12c4b 100644 > --- a/drivers/staging/iio/light/Makefile > +++ b/drivers/staging/iio/light/Makefile > @@ -5,3 +5,4 @@ > obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o > obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o > obj-$(CONFIG_TSL2583) += tsl2583.o > +obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o > diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c > new file mode 100644 > index 0000000..671f476 > --- /dev/null > +++ b/drivers/staging/iio/light/tsl2x7x_core.c > @@ -0,0 +1,2053 @@ > +/* > + * Device driver for monitoring ambient light intensity in (lux) > + * and proximity detection (prox) within the TAOS TSL2X7X family of devices. > + * > + * Copyright (c) 2012, TAOS Corporation. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, write to the Free Software Foundation, Inc., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + */ > + > +#include<linux/kernel.h> > +#include<linux/i2c.h> > +#include<linux/errno.h> > +#include<linux/delay.h> > +#include<linux/string.h> > +#include<linux/mutex.h> > +#include<linux/unistd.h> > +#include<linux/interrupt.h> > +#include<linux/platform_device.h> > +#include<linux/input.h> > +#include<linux/slab.h> > +#include<linux/pm.h> > +#include<linux/module.h> > +#include<linux/version.h> > + > +#include<linux/cdev.h> > +#include<linux/stat.h> > +#include<linux/module.h> > +#include "tsl2x7x_core.h" > +#include "../events.h" > +#include "../buffer.h" > +#include "../iio.h" > +#include "../sysfs.h" > + > +/* Cal defs*/ > +#define PROX_STAT_CAL 0 > +#define PROX_STAT_SAMP 1 > +#define MAX_SAMPLES_CAL 200 > + > +/* TSL2X7X Device ID */ > +#define TRITON_ID 0x00 > +#define SWORDFISH_ID 0x30 > +#define HALIBUT_ID 0x20 > + > +/* Lux calculation constants */ > +#define TSL2X7X_LUX_CALC_OVER_FLOW 65535 > + > +/* TAOS txx2x7x Device family members */ > +enum { > + tsl2571, > + tsl2671, > + tmd2671, > + tsl2771, > + tmd2771, > + tsl2572, > + tsl2672, > + tmd2672, > + tsl2772, > + tmd2772 > +}; > + > +enum { > + TSL2X7X_CHIP_UNKNOWN = 0, > + TSL2X7X_CHIP_WORKING = 1, > + TSL2X7X_CHIP_SUSPENDED = 2 > +}; > + > +/* Per-device data */ > +struct tsl2x7x_als_info { > + u16 als_ch0; > + u16 als_ch1; > + u16 lux; > +}; > + > +/* proximity data */ > +struct tsl2x7x_prox_info { > + u16 prox_data; > + int prox_event; > +}; > + > +struct prox_stat { > + u16 min; > + u16 max; > + u16 mean; > + unsigned long stddev; > +}; > + > +struct tsl2x7x_settings { > + int als_time; > + int als_gain; > + int als_gain_trim; > + int wait_time; > + int prx_time; > + int prox_gain; > + int prox_config; > + int als_cal_target; > + u8 interrupts_en; > + u8 als_persistence; > + int als_thresh_low; > + int als_thresh_high; > + int prox_thres_low; > + int prox_thres_high; > + int prox_pulse_count; > + int prox_max_samples_cal;/* for calibration mode*/ > + > +}; > + > +struct tsl2X7X_chip_info { > + struct iio_chan_spec channel[0]; > + const struct iio_info *info; > +}; err. what is channel[0] for? Please do the iio_chan_spec stuff fully. > + > +struct tsl2X7X_chip { > + kernel_ulong_t id; > + struct mutex prox_mutex; > + struct mutex als_mutex; > + struct i2c_client *client; > + struct iio_dev *iio_dev; > + struct tsl2x7x_prox_info prox_cur_info; > + struct tsl2x7x_als_info als_cur_info; > + struct tsl2x7x_settings tsl2x7x_settings; > + struct tsl2X7X_platform_data *pdata; > + int als_time_scale; > + int als_saturation; > + int tsl2x7x_chip_status; > + u8 tsl2x7x_config[TSL2X7X_REG_MAX]; > + bool init_done; > + struct work_struct work_thresh; > + s64 event_timestamp; > + /* This structure is intentionally large to accommodate > + * updates via sysfs. */ > + /* Sized to 9 = max 8 segments + 1 termination segment */ > + /* Assumption is one and only one type of glass used */ > + struct tsl2x7x_lux tsl2x7x_device_lux[MAX_TABLE_SIZE]; > +}; > + > +/* Different devices require different coefficents */ > +static const struct tsl2x7x_lux tsl2x71_lux_table[] = { > + { 14461, 611, 1211 }, > + { 18540, 352, 623 }, > + { 0, 0, 0 }, > +}; > + > +static const struct tsl2x7x_lux tmd2x71_lux_table[] = { > + { 11635, 115, 256 }, > + { 15536, 87, 179 }, > + { 0, 0, 0 }, > +}; > + > +static const struct tsl2x7x_lux tsl2x72_lux_table[] = { > + { 14013, 466, 917 }, > + { 18222, 310, 552 }, > + { 0, 0, 0 }, > +}; > + > +static const struct tsl2x7x_lux tmd2x72_lux_table[] = { > + { 13218, 130, 262 }, > + { 17592, 92, 169 }, > + { 0, 0, 0 }, > +}; > + > +static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = { > + [tsl2571] = tsl2x71_lux_table, > + [tsl2671] = tsl2x71_lux_table, > + [tmd2671] = tmd2x71_lux_table, > + [tsl2771] = tsl2x71_lux_table, > + [tmd2771] = tmd2x71_lux_table, > + [tsl2572] = tsl2x72_lux_table, > + [tsl2672] = tsl2x72_lux_table, Check your spacing vs tabs. > + [tmd2672] = tmd2x72_lux_table, > + [tsl2772] = tsl2x72_lux_table, > + [tmd2772] = tmd2x72_lux_table, > +}; > + > +struct als_gainadj { > + s16 ch0; > + s16 ch1; > +}; > + > +/* Used to validate the ALS gain selection index */ > +static const struct als_gainadj tsl2X7X_als_gainadj[] = { > + { 1, 1 }, > + { 8, 8 }, > + { 16, 16 }, > + { 120, 120 } > +}; This is a somewhat novel structure.... Any real point in the two columns? > + > + > +/* Not using channels */ > +static const struct iio_chan_spec tsl2X7X_channels[] = {}; > + > +/* > + * Read a number of bytes starting at register (reg) location. > + * Return 0, or i2c_smbus_write_byte ERROR code. > + */ > +static int > +tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val, unsigned int len) > +{ > + int ret; > + int i; > + > + for (i = 0; i< len; i++) { Just to check, does this correspond to i2c_smbus_read_byte_data(client, (TSL2X7X_CMD_REG | REG))? Also, a quick look makes me think you only ever use this for one byte at a time... > + /* select register to write */ > + ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg)); > + if (ret< 0) { > + dev_err(&client->dev, "tsl2x7x_i2c_read failed to write" > + " register %x\n", reg); > + return ret; > + } > + /* read the data */ > + *val = i2c_smbus_read_byte(client); > + val++; > + reg++; > + } > + return 0; > +} > + > +/* Kernel doc please. > + * Reads and calculates current lux value. > + * The raw ch0 and ch1 values of the ambient light sensed in the last > + * integration cycle are read from the device. > + * Time scale factor array values are adjusted based on the integration time. > + * The raw values are multiplied by a scale factor, and device gain is obtained > + * using gain index. Limit checks are done next, then the ratio of a multiple > + * of ch1 value, to the ch0 value, is calculated. The array tsl2x7x_device_lux[] > + * declared above is then scanned to find the first ratio value that is just > + * above the ratio we just calculated. The ch0 and ch1 multiplier constants in > + * the array are then used along with the time scale factor array values, to > + * calculate the lux. > + */ > +static int tsl2x7x_get_lux(struct iio_dev *indio_dev) > +{ > + u16 ch0, ch1; /* separated ch0/ch1 data from device */ > + u32 lux; /* raw lux calculated from device data */ > + u64 lux64; > + u32 ratio; > +#pragma pack(4) ? that needs some explanation... > + u8 buf[4]; > + struct tsl2x7x_lux *p; > + struct tsl2X7X_chip *chip = iio_priv(indio_dev); > + int i, ret; > + u32 ch0lux = 0; > + u32 ch1lux = 0; > + as below, I find these try locks rather suspicious. Please justify. > + if (mutex_trylock(&chip->als_mutex) == 0) { > + dev_info(&chip->client->dev, "tsl2x7x_get_lux device is busy\n"); > + return chip->als_cur_info.lux; /* busy, so return LAST VALUE */ > + } > + > + if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) { > + /* device is not enabled */ > + dev_err(&chip->client->dev, "tsl2x7x_get_lux device is not enabled\n"); > + ret = -EBUSY ; > + goto out_unlock; > + } > + > + ret = tsl2x7x_i2c_read(chip->client, > + (TSL2X7X_CMD_REG | TSL2X7X_STATUS),&buf[0], 1); > + if (ret< 0) { > + dev_err(&chip->client->dev, > + "tsl2x7x_get_lux failed to read CMD_REG\n"); > + goto out_unlock; > + } > + /* is data new& valid */ > + if (!(buf[0]& TSL2X7X_STA_ADC_VALID)) { > + dev_err(&chip->client->dev, > + "tsl2x7x_get_lux data not valid yet\n"); > + ret = chip->als_cur_info.lux; /* return LAST VALUE */ > + goto out_unlock; > + } > + > + for (i = 0; i< 4; i++) { > + ret = tsl2x7x_i2c_read(chip->client, > + (TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i)), > + &buf[i], 1); > + if (ret< 0) { > + dev_err(&chip->client->dev, > + "tsl2x7x_get_lux failed to read" > + " ret: %x\n", ret); > + goto out_unlock; > + } > + } > + > + /* clear status, really interrupt status ( are off), > + but we use the bit anyway */ > + ret = i2c_smbus_write_byte(chip->client, > + (TSL2X7X_CMD_REG | > + TSL2X7X_CMD_SPL_FN | > + TSL2X7X_CMD_ALS_INT_CLR)); > + > + if (ret< 0) { > + dev_err(&chip->client->dev, > + "tsl2x7x_i2c_write_command failed in tsl2x7x_get_lux, err = %d\n", > + ret); > + goto out_unlock; /* have no data, so return failure */ > + } > + > + /* extract ALS/lux data */ > + ch0 = le16_to_cpup((const __le16 *)&buf[0]); > + ch1 = le16_to_cpup((const __le16 *)&buf[2]); > + > + chip->als_cur_info.als_ch0 = ch0; > + chip->als_cur_info.als_ch1 = ch1; > + > + if ((ch0>= chip->als_saturation) || (ch1>= chip->als_saturation)) > + goto return_max; > + > + if (ch0 == 0) { > + /* have no data, so return LAST VALUE */ > + ret = chip->als_cur_info.lux = 0; > + goto out_unlock; > + } > + /* calculate ratio */ > + ratio = (ch1<< 15) / ch0; > + /* convert to unscaled lux using the pointer to the table */ > + for (p = (struct tsl2x7x_lux *) chip->tsl2x7x_device_lux; > + p->ratio != 0&& p->ratio< ratio; p++) stray semi colon. > + ; > + > + if (p->ratio == 0) { > + lux = 0; > + } else { > + ch0lux = ((ch0 * p->ch0) + > + (tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch0>> 1)) > + / tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch0; > + > + ch1lux = ((ch1 * p->ch1) + > + (tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch1>> 1)) > + / tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch1; > + > + lux = ch0lux - ch1lux; > + } > + > + /* note: lux is 31 bit max at this point */ > + if (ch1lux> ch0lux) { > + dev_dbg(&chip->client->dev, "No Data - Return last value\n"); > + ret = chip->als_cur_info.lux = 0; > + goto out_unlock; > + } > + > + /* adjust for active time scale */ > + if (chip->als_time_scale == 0) > + lux = 0; > + else > + lux = (lux + (chip->als_time_scale>> 1)) / > + chip->als_time_scale; > + > + /* adjust for active gain scale > + * The tsl2x7x_device_lux tables have a factor of 256 built-in. > + * User-specified gain provides a multiplier. > + * Apply user-specified gain before shifting right to retain precision. > + * Use 64 bits to avoid overflow on multiplication. > + * Then go back to 32 bits before division to avoid using div_u64(). > + */ > + lux64 = lux; > + lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim; > + lux64>>= 8; > + lux = lux64; > + lux = (lux + 500) / 1000; > + > + if (lux> TSL2X7X_LUX_CALC_OVER_FLOW) { /* check for overflow */ > +return_max: > + lux = TSL2X7X_LUX_CALC_OVER_FLOW; > + } > + > + /* Update the structure with the latest VALID lux. */ > + chip->als_cur_info.lux = lux; > + ret = lux; > + > +out_unlock: > + mutex_unlock(&chip->als_mutex); > + return ret; > + > +} > + > +/* > + * Proximity poll function - if valid data is available, read and form the ch0 > + * and prox data values, check for limits on the ch0 value, and check the prox > + * data against the current thresholds, to set the event status accordingly. > + */ > +static int tsl2x7x_prox_poll(struct iio_dev *indio_dev) > +{ > +#define CONSECUTIVE_RETRIES 50 > + > + int i; > + int ret; > + u8 status; > + u8 chdata[2]; > + int err_cnt; > + struct tsl2X7X_chip *chip = iio_priv(indio_dev); > + > + if (mutex_trylock(&chip->prox_mutex) == 0) { > + dev_err(&chip->client->dev, "Can't get prox mutex\n"); > + return -EBUSY; > + } Trylocks always need an explanation as far as I am concerned. why not wait? > + > + err_cnt = 0; > + > +try_again: > + ret = tsl2x7x_i2c_read(chip->client, > + (TSL2X7X_CMD_REG | TSL2X7X_STATUS),&status, 1); > + if (ret< 0) { > + dev_err(&chip->client->dev, > + "Read regs failed in tsl2x7x_prox_poll() - A\n"); > + mutex_unlock(&chip->prox_mutex); > + return ret; > + } > + > + /*Prox interrupt asserted*/ > + if (((chip->tsl2x7x_settings.interrupts_en<< 4) > + & CNTL_PROX_INT_ENBL)) { > + if (!(status& TSL2X7X_STA_ADC_VALID)) { I've not read the datasheet but this seems unusual. You get an interrupt but the value isn't valid? > + err_cnt++; > + if (err_cnt> CONSECUTIVE_RETRIES) { > + mutex_unlock(&chip->prox_mutex); > + dev_err(&chip->client->dev, > + "Consec. retries exceeded\n"); > + return chip->prox_cur_info.prox_event; > + } > + goto try_again; > + } > + } > + > + for (i = 0; i< 2; i++) { > + ret = tsl2x7x_i2c_read(chip->client, > + (TSL2X7X_CMD_REG | > + (TSL2X7X_PRX_LO + i)),&chdata[i], 1); > + if (ret< 0) { Errors like this are extremely unlikely (I hope) so I'd drop the message. Also use a goto and have the mutex_unlock in only one place as it's easier to read. > + dev_err(&chip->client->dev, > + "Read regs failed in tsl2x7x_prox_poll() - B\n"); > + mutex_unlock(&chip->prox_mutex); > + return ret; > + } > + } > + > + chip->prox_cur_info.prox_data = (chdata[1]<<8)|chdata[0]; > + > + if (chip->prox_cur_info.prox_data>= > + chip->tsl2x7x_settings.prox_thres_high) > + chip->prox_cur_info.prox_event = 1; > + else > + chip->prox_cur_info.prox_event = 0; use chip->proc_cur_info.prox_event = chip->prox_cur_info.prox_data >= chip->tsl2x7x_settings.prox_thresh_high; > + > + mutex_unlock(&chip->prox_mutex); > + return chip->prox_cur_info.prox_event; > +} > + > +/* > + * Provides initial operational parameter defaults. > + * These defaults may be changed through the device's sysfs files. > + */ Have a const static struct tsl2x7x_settings tsl2x7x_defaults = { .als_time = 200, ... }; then memcpy it into place as necessary. > +static void tsl2x7x_defaults(struct tsl2X7X_chip *chip) > +{ > + /* Operational parameters */ > + chip->tsl2x7x_settings.als_time = 200; > + /* must be a multiple of 50mS */ > + chip->tsl2x7x_settings.als_gain = 0; > + /* this is actually an index into the gain table */ > + chip->tsl2x7x_settings.prx_time = 0xfe; /*5.4 mS */ > + /* 2.7ms prox integration time - decrease to increase time */ > + /* decreases in 2.7 ms intervals */ > + chip->tsl2x7x_settings.prox_gain = 1; > + /* these are bits 3:2 of reg 0x0f: 0=x1,1=x2,2=x4,3=x8 */ > + /* assume clear glass as default */ > + chip->tsl2x7x_settings.wait_time = 245; > + /* Time between PRX and ALS cycles -decrease to increase time */ > + /* decreases in 2.7 ms intervals */ > + chip->tsl2x7x_settings.prox_config = 0; > + /* Prox configuration filters */ > + chip->tsl2x7x_settings.als_gain_trim = 1000; > + /* default gain trim to account for aperture effects */ > + chip->tsl2x7x_settings.als_cal_target = 150; > + /* Known external ALS reading used for calibration */ > + chip->tsl2x7x_settings.als_thresh_low = 200; > + /* CH0 'low' count to trigger interrupt */ > + chip->tsl2x7x_settings.als_thresh_high = 256; > + /* CH0 'high' count to trigger interrupt */ > + chip->tsl2x7x_settings.als_persistence = 0xFF; > + /* Number of 'out of limits' ADC readings PRX/ALS*/ > + chip->tsl2x7x_settings.interrupts_en = 0x00; > + /* Default interrupt(s) enabled. > + * 0x00 = none, 0x10 = als, 0x20 = prx 0x30 = bth */ > + chip->tsl2x7x_settings.prox_thres_low = 0; > + chip->tsl2x7x_settings.prox_thres_high = 512; > + /*default threshold (adjust either manually or with cal routine*/ > + chip->tsl2x7x_settings.prox_max_samples_cal = 30; > + chip->tsl2x7x_settings.prox_pulse_count = 8; > + > + /* Load up the lux table. Can be changed later via ABI */ > + if (chip->pdata&& chip->pdata->platform_lux_table[0].ratio != 0) > + memcpy(chip->tsl2x7x_device_lux, > + chip->pdata->platform_lux_table, > + sizeof(chip->pdata->platform_lux_table)); > + else > + memcpy(chip->tsl2x7x_device_lux, > + (struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id], > + MAX_DEFAULT_TABLE_BYTES); > + > +} > + As I've stated below, you really need to justify why we have calibration in the kernel rather than userspace.. > +/* > + * Obtain single reading and calculate the als_gain_trim > + * (later used to derive actual lux). > + * Return updated gain_trim value. > + */ > +static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev) > +{ > + struct tsl2X7X_chip *chip = iio_priv(indio_dev); > + u8 reg_val; > + int gain_trim_val; > + int ret; > + int lux_val; > + > + ret = i2c_smbus_write_byte(chip->client, > + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); > + if (ret< 0) { > + dev_err(&chip->client->dev, > + "tsl2x7x_als_calibrate failed to write CNTRL register, ret=%d\n", > + ret); > + return ret; > + } > + > + reg_val = i2c_smbus_read_byte(chip->client); > + if ((reg_val& (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) > + != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) { > + dev_err(&chip->client->dev, > + "tsl2x7x_als_calibrate failed: ADC not enabled\n"); > + return -1; > + } > + > + ret = i2c_smbus_write_byte(chip->client, > + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); > + if (ret< 0) { > + dev_err(&chip->client->dev, > + "tsl2x7x_als_calibrate failed to write ctrl reg: ret=%d\n", > + ret); > + return ret; > + } > + reg_val = i2c_smbus_read_byte(chip->client); > + > + if ((reg_val& TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) { > + dev_err(&chip->client->dev, > + "tsl2x7x_als_calibrate failed: STATUS - ADC not valid.\n"); > + return -ENODATA; > + } > + lux_val = tsl2x7x_get_lux(indio_dev); > + if (lux_val< 0) { > + dev_err(&chip->client->dev, > + "tsl2x7x_als_calibrate failed to get lux\n"); > + return lux_val; > + } > + gain_trim_val = (((chip->tsl2x7x_settings.als_cal_target) > + * chip->tsl2x7x_settings.als_gain_trim) / lux_val); > + > + if ((gain_trim_val< 250) || (gain_trim_val> 4000)) > + return -ERANGE; > + > + chip->tsl2x7x_settings.als_gain_trim = gain_trim_val; > + > + dev_info(&chip->client->dev, > + "%s als_calibrate completed\n", chip->client->name); > + > + return (int) gain_trim_val; > +} > + > +/* > + * Turn the device on. > + * Configuration must be set before calling this function. > + */ > +static int tsl2x7x_chip_on(struct iio_dev *indio_dev) > +{ > + int i; > + int ret = 0; > + u8 *dev_reg; > + u8 utmp; > + int als_count; > + int als_time; > + struct tsl2X7X_chip *chip = iio_priv(indio_dev); > + u8 reg_val = 0; > + > + if (chip->pdata&& chip->pdata->power_on) > + chip->pdata->power_on(indio_dev); > + > + /* Non calculated parameters */ > + chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = > + chip->tsl2x7x_settings.prx_time; > + chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = > + chip->tsl2x7x_settings.wait_time; > + chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] = > + chip->tsl2x7x_settings.prox_config; > + > + chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] = > + (chip->tsl2x7x_settings.als_thresh_low)& 0xFF; > + chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] = > + (chip->tsl2x7x_settings.als_thresh_low>> 8)& 0xFF; > + chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] = > + (chip->tsl2x7x_settings.als_thresh_high)& 0xFF; > + chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] = > + (chip->tsl2x7x_settings.als_thresh_high>> 8)& 0xFF; > + chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] = > + chip->tsl2x7x_settings.als_persistence; > + > + chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] = > + chip->tsl2x7x_settings.prox_pulse_count; > + chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] = > + chip->tsl2x7x_settings.prox_thres_low; > + chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] = > + chip->tsl2x7x_settings.prox_thres_high; > + > + /* and make sure we're not already on */ > + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { > + /* if forcing a register update - turn off, then on */ > + dev_info(&chip->client->dev, "device is already enabled\n"); > + return -EINVAL; > + } > + > + /* determine als integration regster */ > + als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270; > + if (als_count == 0) > + als_count = 1; /* ensure at least one cycle */ > + > + /* convert back to time (encompasses overrides) */ > + als_time = (als_count * 27 + 5) / 10; > + chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count; > + > + /* Set the gain based on tsl2x7x_settings struct */ > + chip->tsl2x7x_config[TSL2X7X_GAIN] = > + (chip->tsl2x7x_settings.als_gain | (mA100 | DIODE1) > + | ((chip->tsl2x7x_settings.prox_gain)<< 2)); > + > + /* set chip struct re scaling and saturation */ > + chip->als_saturation = als_count * 922; /* 90% of full scale */ > + chip->als_time_scale = (als_time + 25) / 50; > + > + /* TSL2X7X Specific power-on / adc enable sequence > + * Power on the device 1st. */ > + utmp = TSL2X7X_CNTL_PWR_ON; > + ret = i2c_smbus_write_byte_data(chip->client, > + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); > + if (ret< 0) { > + dev_err(&chip->client->dev, "tsl2x7x_chip_on failed on CNTRL reg.\n"); > + return -1; > + } > + > + /* Use the following shadow copy for our delay before enabling ADC. > + * Write all the registers. */ > + for (i = 0, dev_reg = chip->tsl2x7x_config; i< TSL2X7X_REG_MAX; i++) { > + ret = i2c_smbus_write_byte_data(chip->client, > + TSL2X7X_CMD_REG + i, *dev_reg++); > + if (ret< 0) { > + dev_err(&chip->client->dev, > + "tsl2x7x_chip_on failed on write to reg %d.\n", i); > + return ret; > + } > + } > + > + udelay(3000); /* Power-on settling time */ > + > + /* NOW enable the ADC > + * initialize the desired mode of operation */ > + utmp = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL | CNTL_PROX_DET_ENBL; > + ret = i2c_smbus_write_byte_data(chip->client, > + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); > + if (ret< 0) { > + dev_err(&chip->client->dev, "tsl2x7x_chip_on failed on 2nd CTRL reg.\n"); > + return ret; > + } > + > + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING; > + > + if (chip->tsl2x7x_settings.interrupts_en != 0) { > + dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n"); > + /* first time interrupt */ > + chip->init_done = 0; > + > + > + reg_val = TSL2X7X_CNTL_PWR_ON; > + > + if (chip->tsl2x7x_settings.interrupts_en == 0x10) > + reg_val |= CNTL_ADC_ENBL; > + > + if (chip->tsl2x7x_settings.interrupts_en == 0x20) > + reg_val |= CNTL_PROX_DET_ENBL; > + > + if (chip->tsl2x7x_settings.interrupts_en == 0x30) > + reg_val |= (CNTL_ADC_ENBL | CNTL_PROX_DET_ENBL); > + > + reg_val |= chip->tsl2x7x_settings.interrupts_en; > + > + ret = i2c_smbus_write_byte_data(chip->client, > + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL), reg_val); > + if (ret< 0) > + dev_err(&chip->client->dev, > + "tsl2x7x_i2c_write to device failed in tsl2x7x_IOCTL_INT_SET.\n"); > + > + /* Clear out any initial interrupts */ > + ret = i2c_smbus_write_byte(chip->client, > + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | > + TSL2X7X_CMD_PROXALS_INTCLR); > + if (ret< 0) { > + dev_err(&chip->client->dev, > + "tsl2x7x_i2c_write_command failed in tsl2x7x_chip_on\n"); > + return ret; > + } > + } > + return ret; > + > +} > + > +static int tsl2x7x_chip_off(struct iio_dev *indio_dev) > +{ > + int ret; > + struct tsl2X7X_chip *chip = iio_priv(indio_dev); > + > + /* turn device off */ > + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; > + > + ret = i2c_smbus_write_byte_data(chip->client, > + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00); > + > + if (chip->pdata&& chip->pdata->power_off) > + chip->pdata->power_off(chip->client); > + > + return ret; > +} > + > +/** > + * Integer Square Root > + * We need an integer version since 1st Floating point is not allowed > + * in driver world, 2nd, cannot count on the devices having a FPU, and > + * 3rd software FP emulation may be excessive. It's exactly this sort of thing that supports my argument below that this ought to be in userspace... > + */ > +static unsigned long tsl2x7x_isqrt(unsigned long x) > +{ > + register unsigned long op, res, one; > + op = x; > + res = 0; > + > + one = 1<< 30; > + while (one> op) > + one>>= 2; > + > + while (one != 0) { > + if (op>= res + one) { > + op -= res + one; > + res += one<< 1; > + } > + res>>= 1; > + one>>= 2; > + } > + return res; > +} > + > +/* > + * Proximity calibration helper function > + * runs through a collection of data samples, > + * sets the min, max, mean, and std dev. > + */ > +static > +void tsl2x7x_prox_calculate(u16 *data, int length, struct prox_stat *statP) > +{ > + int i; > + int min, max, sum, mean; > + unsigned long stddev; > + int tmp; > + > + if (length == 0) > + length = 1; > + > + sum = 0; > + min = 0xffff; > + max = 0; > + for (i = 0; i< length; i++) { > + sum += data[i]; > + if (data[i]< min) > + min = data[i]; > + if (data[i]> max) > + max = data[i]; > + } > + mean = sum/length; > + statP->min = min; > + statP->max = max; > + statP->mean = mean; > + > + sum = 0; > + for (i = 0; i< length; i++) { > + tmp = data[i]-mean; > + sum += tmp * tmp; > + } > + stddev = tsl2x7x_isqrt((long)sum)/length; > + statP->stddev = stddev; > + > +} > + > +/** > + * Proximity calibration - collects a number of samples, > + * calculates a standard deviation based on the samples, and > + * sets the threshold accordingly. > + */ I guess you have a demand for this, but generally I'd feel this had more of a place in userspace than down in the kernel... > +static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) > +{ > + u16 prox_history[MAX_SAMPLES_CAL+1]; > + int i; > + struct prox_stat prox_stat_data[2]; > + struct prox_stat *calP; > + struct tsl2X7X_chip *chip = iio_priv(indio_dev); > + u8 tmp_irq_settings; > + u8 current_state = chip->tsl2x7x_chip_status; > + > + if (chip->tsl2x7x_settings.prox_max_samples_cal> MAX_SAMPLES_CAL) { > + dev_err(&chip->client->dev, > + "max prox samples cal is too big: %d\n", > + chip->tsl2x7x_settings.prox_max_samples_cal); > + chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL; > + } > + > + /* have to stop to change settings */ > + tsl2x7x_chip_off(indio_dev); > + > + /* Enable proximity detection save just in case prox not wanted yet*/ > + tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en; > + chip->tsl2x7x_settings.interrupts_en |= CNTL_PROX_INT_ENBL; > + > + /*turn on device if not already on*/ > + tsl2x7x_chip_on(indio_dev); > + > + /*gather the samples*/ > + for (i = 0; i< chip->tsl2x7x_settings.prox_max_samples_cal; i++) { > + mdelay(15); > + tsl2x7x_prox_poll(indio_dev); > + prox_history[i] = chip->prox_cur_info.prox_data; > + dev_info(&chip->client->dev, "2 i=%d prox data= %d\n", > + i, chip->prox_cur_info.prox_data); > + > + } > + > + tsl2x7x_chip_off(indio_dev); > + > + calP =&prox_stat_data[PROX_STAT_CAL]; > + tsl2x7x_prox_calculate(prox_history, > + chip->tsl2x7x_settings.prox_max_samples_cal, calP); > + chip->tsl2x7x_settings.prox_thres_high = (calP->max<< 1) - calP->mean; > + > + dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n", > + calP->min, calP->mean, calP->max); > + dev_info(&chip->client->dev, > + "%s proximity threshold set to %d\n", > + chip->client->name, chip->tsl2x7x_settings.prox_thres_high); > + > + /* back to the way they were */ > + chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings; > + if (current_state == TSL2X7X_CHIP_WORKING) > + tsl2x7x_chip_on(indio_dev); > +} > + > +/* ---------- Sysfs Interface Functions ------------- */ Don't bother with the structure comments. It's readily apparent and they have a nasty habit of not being true after a year or two. > + > + > +static ssize_t tsl2x7x_power_state_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status); > +} > + > +static ssize_t tsl2x7x_power_state_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; strtobool > + > + if (value == 0) > + tsl2x7x_chip_off(dev_info); > + else > + tsl2x7x_chip_on(dev_info); > + > + return len; > +} > + > +static ssize_t tsl2x7x_proximity_detect_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + tsl2x7x_prox_poll(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + chip->prox_cur_info.prox_event); > +} > + > +static ssize_t tsl2x7x_gain_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch0); > +} > + > +static ssize_t tsl2x7x_gain_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + switch (value) { > + case 1: > + chip->tsl2x7x_settings.als_gain = 0; > + break; > + case 8: > + chip->tsl2x7x_settings.als_gain = 1; > + break; > + case 16: > + chip->tsl2x7x_settings.als_gain = 2; > + break; > + case 120: > + chip->tsl2x7x_settings.als_gain = 3; > + break; It's unlikely but you probably want to verify that 120 is only used for parts where it is valid. (for consistency sake). > + case 128: > + chip->tsl2x7x_settings.als_gain = 3; > + break; > + > + default: > + dev_err(dev, > + "Invalid Gain Index\n"); > + return -EINVAL; > + } > + > + return len; > +} > + > +static ssize_t tsl2x7x_gain_available_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + if (strncmp(chip->client->name, "tsl2772", 7) == 0) > + return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128"); > + else > + return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120"); > +} > + > +static ssize_t tsl2x7x_prox_gain_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + (1<< chip->tsl2x7x_settings.prox_gain)); > +} > + > +static ssize_t tsl2x7x_prox_gain_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + switch (value) { > + case 1: maybe use the relevant log2? Then you just need to check if it's too big. > + chip->tsl2x7x_settings.prox_gain = 0; > + break; > + case 2: > + chip->tsl2x7x_settings.prox_gain = 1; > + break; > + case 4: > + chip->tsl2x7x_settings.prox_gain = 2; > + break; > + case 8: > + chip->tsl2x7x_settings.prox_gain = 3; > + break; > + default: > + dev_err(dev, > + "Invalid Prox Gain Index\n"); > + return -EINVAL; > + } > + > + return len; > +} > + > +static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8"); > +} > + > +static ssize_t tsl2x7x_als_time_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + chip->tsl2x7x_settings.als_time); > +} > + > +static ssize_t tsl2x7x_als_time_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + if ((value< 50) || (value> 650)) > + return -EINVAL; > + > + if (value % 50) > + return -EINVAL; > + > + chip->tsl2x7x_settings.als_time = value; > + > + return len; > +} > + > +static ssize_t tsl2x7x_als_time_available_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + return snprintf(buf, PAGE_SIZE, "%s\n", > + "50 100 150 200 250 300 350 400 450 500 550 600 650"); > +} > + > +static ssize_t tsl2x7x_als_trim_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + chip->tsl2x7x_settings.als_gain_trim); > +} > + > +static ssize_t tsl2x7x_als_trim_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + if (value) I'd have thought 0 was a valid gain_trim? > + chip->tsl2x7x_settings.als_gain_trim = value; > + > + return len; > +} > + > +static ssize_t tsl2x7x_als_cal_target_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + chip->tsl2x7x_settings.als_cal_target); > +} > + > +static ssize_t tsl2x7x_als_cal_target_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + if (value) > + chip->tsl2x7x_settings.als_cal_target = value; > + > + return len; > +} > + > +static ssize_t tsl2x7x_interrupts_en_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + if (chip->tsl2x7x_settings.interrupts_en& 0x10) > + return snprintf(buf, PAGE_SIZE, "%d\n", 1); > + else > + return snprintf(buf, PAGE_SIZE, "%d\n", 0); snprintf(buf, PAGE_SIZE, "%d\n", !!(chip->tsl2x7x_settings.interrupts_en & 0x10)); > +} > + > +static ssize_t tsl2x7x_interrupts_en_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + strotobool (and use the iio_chan_spec and relevant callbacks please.) > + if (value> 1) > + return -EINVAL; > + if (value) > + chip->tsl2x7x_settings.interrupts_en |= 0x10; > + else > + chip->tsl2x7x_settings.interrupts_en&= 0x20; > + > + return len; > +} > + > +static ssize_t tsl2x7x_prox_interrupt_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + if (chip->tsl2x7x_settings.interrupts_en& 0x20) > + return snprintf(buf, PAGE_SIZE, "%d\n", 1); > + else > + return snprintf(buf, PAGE_SIZE, "%d\n", 0); > +} > + > +static ssize_t tsl2x7x_prox_interrupt_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + if (value> 1) > + return -EINVAL; > + if (value) > + chip->tsl2x7x_settings.interrupts_en |= 0x20; > + else > + chip->tsl2x7x_settings.interrupts_en&= 0x10; > + > + return len; > +} > + > +static ssize_t tsl2x7x_als_thresh_low_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + chip->tsl2x7x_settings.als_thresh_low); > +} > + > +static ssize_t tsl2x7x_als_thresh_low_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + chip->tsl2x7x_settings.als_thresh_low = value; > + > + return len; > +} > + > +static ssize_t tsl2x7x_als_thresh_high_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + chip->tsl2x7x_settings.als_thresh_high); > +} > + > +static ssize_t tsl2x7x_als_thresh_high_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + chip->tsl2x7x_settings.als_thresh_high = value; > + > + return len; > +} > + > +static ssize_t tsl2x7x_prox_thresh_low_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + chip->tsl2x7x_settings.prox_thres_low); > +} > + > +static ssize_t tsl2x7x_prox_thresh_low_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + chip->tsl2x7x_settings.prox_thres_low = value; > + > + return len; > +} > + > +static ssize_t tsl2x7x_prox_thresh_high_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + chip->tsl2x7x_settings.prox_thres_high); > +} > + > +static ssize_t tsl2x7x_prox_thresh_high_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + chip->tsl2x7x_settings.prox_thres_high = value; > + > + return len; > +} > + > +static ssize_t tsl2x7x_prox_data_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + tsl2x7x_prox_poll(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", > + chip->prox_cur_info.prox_data); > +} > + > +/* sampling_frequency AKA persistence in data sheet */ > +static ssize_t tsl2x7x_als_persistence_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "0x%02X\n", > + chip->tsl2x7x_settings.als_persistence); > +} > + > +static ssize_t tsl2x7x_als_persistence_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; > + > + chip->tsl2x7x_settings.als_persistence = value; > + > + return len; > +} > + > +static > +ssize_t tsl2x7x_als_persistence_available_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + return snprintf(buf, PAGE_SIZE, "0x00 - 0xFF (0 - 255)\n"); > +} > + > +static > +ssize_t tsl2x7x_lux_show(struct device *dev, struct device_attribute *attr, > + char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + int lux; > + > + lux = tsl2x7x_get_lux(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "%d\n", lux); > +} > + > +static > +ssize_t tsl2x7x_adc_show(struct device *dev, struct device_attribute *attr, > + char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + tsl2x7x_get_lux(dev_info); > + > + return snprintf(buf, PAGE_SIZE, "0x%08x\n", > + ((chip->als_cur_info.als_ch0<< 16) | > + chip->als_cur_info.als_ch1)); Your outputing in hex? Please don't and please do this through an iio_chan_spec structure and read_raw callback. > +} > + > +static ssize_t tsl2x7x_do_calibrate(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; strtobool? > + > + if (value == 1) > + tsl2x7x_als_calibrate(dev_info); > + > + return len; > +} > + > +static ssize_t tsl2x7x_luxtable_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + int i; > + int offset = 0; > + > + i = 0; > + while (i< (MAX_TABLE_SIZE * 3)) { > + offset += snprintf(buf + offset, PAGE_SIZE, "%d,%d,%d,", > + chip->tsl2x7x_device_lux[i].ratio, > + chip->tsl2x7x_device_lux[i].ch0, > + chip->tsl2x7x_device_lux[i].ch1); > + if (chip->tsl2x7x_device_lux[i].ratio == 0) { > + /* We just printed the first "0" entry. > + * Now get rid of the extra "," and break. */ > + offset--; > + break; > + } > + i++; > + } > + > + offset += snprintf(buf + offset, PAGE_SIZE, "\n"); > + return offset; > +} > + > +static ssize_t tsl2x7x_luxtable_store(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + int value[ARRAY_SIZE(chip->tsl2x7x_device_lux)*3 + 1]; > + int n; > + > + get_options(buf, ARRAY_SIZE(value), value); > + > + /* We now have an array of ints starting at value[1], and > + * enumerated by value[0]. > + * We expect each group of three ints is one table entry, > + * and the last table entry is all 0. > + */ > + n = value[0]; > + if ((n % 3) || n< 6 || > + n> ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) { > + dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n); > + return -EINVAL; > + } > + > + if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) { > + dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n); > + return -EINVAL; > + } > + > + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) > + tsl2x7x_chip_off(dev_info); > + > + /* Zero out the table */ > + memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux)); > + memcpy(chip->tsl2x7x_device_lux,&value[1], (value[0] * 4)); > + > + return len; > +} > + > +static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev, > + struct device_attribute *attr, const char *buf, size_t len) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + unsigned long value; > + > + if (kstrtoul(buf, 0,&value)) > + return -EINVAL; strtobool probably? > + > + if (value == 1) > + tsl2x7x_prox_cal(dev_info); > + > + return len; > +} > + > +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, > + tsl2x7x_power_state_show, tsl2x7x_power_state_store); > + > +static DEVICE_ATTR(proximity_raw, S_IRUGO, > + tsl2x7x_proximity_detect_show, NULL); > + > +static DEVICE_ATTR(intensity_infrared_raw, S_IRUGO, > + tsl2x7x_prox_data_show, NULL); > + > + > +static DEVICE_ATTR(proximity_calibscale, S_IRUGO | S_IWUSR, > + tsl2x7x_prox_gain_show, tsl2x7x_prox_gain_store); > +static DEVICE_ATTR(proximity_calibscale_available, S_IRUGO, > + tsl2x7x_prox_gain_available_show, NULL); > + > +static DEVICE_ATTR(illuminance0_calibscale, S_IRUGO | S_IWUSR, > + tsl2x7x_gain_show, tsl2x7x_gain_store); > +static DEVICE_ATTR(illuminance0_calibscale_available, S_IRUGO, > + tsl2x7x_gain_available_show, NULL); > + > +static DEVICE_ATTR(illuminance0_integration_time, S_IRUGO | S_IWUSR, > + tsl2x7x_als_time_show, tsl2x7x_als_time_store); > +static DEVICE_ATTR(illuminance0_integration_time_available, S_IRUGO, > + tsl2x7x_als_time_available_show, NULL); > + > +static DEVICE_ATTR(illuminance0_calibbias, S_IRUGO | S_IWUSR, > + tsl2x7x_als_trim_show, tsl2x7x_als_trim_store); > + > +static DEVICE_ATTR(illuminance0_input_target, S_IRUGO | S_IWUSR, > + tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store); > + > +static DEVICE_ATTR(illuminance0_both_raw, S_IRUGO, tsl2x7x_adc_show, > + NULL); > + > +static DEVICE_ATTR(illuminance0_input, S_IRUGO, tsl2x7x_lux_show, > + NULL); > +static DEVICE_ATTR(illuminance0_calibrate, S_IWUSR, NULL, > + tsl2x7x_do_calibrate); > +static DEVICE_ATTR(proximity_calibrate, S_IWUSR, NULL, > + tsl2x7x_do_prox_calibrate); > + > +static DEVICE_ATTR(illuminance0_lux_table, S_IRUGO | S_IWUSR, > + tsl2x7x_luxtable_show, tsl2x7x_luxtable_store); > + > +static DEVICE_ATTR(illuminance0_thresh_falling_value, S_IRUGO | S_IWUSR, > + tsl2x7x_als_thresh_low_show, tsl2x7x_als_thresh_low_store); > + > +static DEVICE_ATTR(illuminance0_thresh_rising_value, S_IRUGO | S_IWUSR, > + tsl2x7x_als_thresh_high_show, tsl2x7x_als_thresh_high_store); > + > +static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR, > + tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store); > + > +static DEVICE_ATTR(sampling_frequency_available, S_IRUGO, > + tsl2x7x_als_persistence_available_show, NULL); > + > +static DEVICE_ATTR(proximity_thresh_rising_value, S_IRUGO | S_IWUSR, > + tsl2x7x_prox_thresh_high_show, tsl2x7x_prox_thresh_high_store); > + > +static DEVICE_ATTR(proximity_thresh_falling_value, S_IRUGO | S_IWUSR, > + tsl2x7x_prox_thresh_low_show, tsl2x7x_prox_thresh_low_store); > + A lot of what we having in here is standard and should be done via a iio_chan_spec definition. That'll cover calibscal, calibbias, input, raw, thresh_rising_value, thresh_falling_value (which incidentally should be in the event attributes). That leaves us with power_state - ideally not here but handled via a kernel wide control (it gets suggested, everyone agrees it's a good idea and no one implements it...) but such is life. calibscale_available - fine integration_time - Propose adding this to the iio_chan_spec via info_mask. integration_time_available - fine. input_target -> target_input but otherwise fine. calibrate -> fine lux_table -> fine sampling_frequency, frequency_available fine. Just for reference, we really need to come up with a way of handing 'available' within the iio_chan_spec structures and the same for sampling frequency. Not your problem but if I say it often enough hopefully someone else will do it ;) > +static struct attribute *tsl2571_device_attrs[] = { > + &dev_attr_power_state.attr, > + &dev_attr_illuminance0_calibscale.attr, > + &dev_attr_illuminance0_calibscale_available.attr, > + &dev_attr_illuminance0_integration_time.attr, > + &dev_attr_illuminance0_integration_time_available.attr, > + &dev_attr_illuminance0_calibbias.attr, > + &dev_attr_illuminance0_input_target.attr, > + &dev_attr_illuminance0_both_raw.attr, > + &dev_attr_illuminance0_input.attr, > + &dev_attr_illuminance0_calibrate.attr, > + &dev_attr_illuminance0_lux_table.attr, > + &dev_attr_illuminance0_thresh_falling_value.attr, > + &dev_attr_illuminance0_thresh_rising_value.attr, > + &dev_attr_sampling_frequency.attr, > + &dev_attr_sampling_frequency_available.attr, > + NULL > +}; > + > +static struct attribute *tsl2671_device_attrs[] = { > + &dev_attr_power_state.attr, > + &dev_attr_proximity_raw.attr, > + &dev_attr_intensity_infrared_raw.attr, > + &dev_attr_sampling_frequency.attr, > + &dev_attr_sampling_frequency_available.attr, > + &dev_attr_proximity_thresh_rising_value.attr, > + &dev_attr_proximity_thresh_falling_value.attr, > + &dev_attr_proximity_calibrate.attr, > + NULL > +}; > + > +static struct attribute *tsl2771_device_attrs[] = { > + &dev_attr_power_state.attr, > + &dev_attr_proximity_raw.attr, > + &dev_attr_intensity_infrared_raw.attr, > + &dev_attr_illuminance0_calibscale.attr, > + &dev_attr_illuminance0_calibscale_available.attr, > + &dev_attr_illuminance0_integration_time.attr, > + &dev_attr_illuminance0_integration_time_available.attr, > + &dev_attr_illuminance0_calibbias.attr, > + &dev_attr_illuminance0_input_target.attr, > + &dev_attr_illuminance0_both_raw.attr, > + &dev_attr_illuminance0_input.attr, > + &dev_attr_illuminance0_calibrate.attr, > + &dev_attr_illuminance0_lux_table.attr, > + &dev_attr_illuminance0_thresh_falling_value.attr, > + &dev_attr_illuminance0_thresh_rising_value.attr, > + &dev_attr_sampling_frequency.attr, > + &dev_attr_sampling_frequency_available.attr, > + &dev_attr_proximity_thresh_rising_value.attr, > + &dev_attr_proximity_thresh_falling_value.attr, > + &dev_attr_proximity_calibrate.attr, > + NULL > +}; > + > +static struct attribute *tsl2572_device_attrs[] = { > + &dev_attr_power_state.attr, > + &dev_attr_illuminance0_calibscale.attr, > + &dev_attr_illuminance0_calibscale_available.attr, > + &dev_attr_illuminance0_integration_time.attr, > + &dev_attr_illuminance0_integration_time_available.attr, > + &dev_attr_illuminance0_calibbias.attr, > + &dev_attr_illuminance0_input_target.attr, > + &dev_attr_illuminance0_both_raw.attr, > + &dev_attr_illuminance0_input.attr, > + &dev_attr_illuminance0_calibrate.attr, > + &dev_attr_illuminance0_lux_table.attr, > + &dev_attr_illuminance0_thresh_falling_value.attr, > + &dev_attr_illuminance0_thresh_rising_value.attr, > + &dev_attr_sampling_frequency.attr, > + &dev_attr_sampling_frequency_available.attr, > + NULL > +}; > + > +static struct attribute *tsl2672_device_attrs[] = { > + &dev_attr_power_state.attr, > + &dev_attr_proximity_raw.attr, > + &dev_attr_intensity_infrared_raw.attr, > + &dev_attr_proximity_calibscale.attr, > + &dev_attr_sampling_frequency.attr, > + &dev_attr_sampling_frequency_available.attr, > + &dev_attr_proximity_thresh_rising_value.attr, > + &dev_attr_proximity_thresh_falling_value.attr, > + &dev_attr_proximity_calibrate.attr, > + NULL > +}; > + Indent the same for all of these. > +static struct attribute *tsl2772_device_attrs[] = { > + &dev_attr_power_state.attr, > + &dev_attr_proximity_raw.attr, > + &dev_attr_proximity_calibscale.attr, > + &dev_attr_intensity_infrared_raw.attr, > + &dev_attr_illuminance0_calibscale.attr, > + &dev_attr_illuminance0_calibscale_available.attr, > + &dev_attr_illuminance0_integration_time.attr, > + &dev_attr_illuminance0_integration_time_available.attr, > + &dev_attr_illuminance0_calibbias.attr, > + &dev_attr_illuminance0_input_target.attr, > + &dev_attr_illuminance0_both_raw.attr, > + &dev_attr_illuminance0_input.attr, > + &dev_attr_illuminance0_calibrate.attr, > + &dev_attr_illuminance0_lux_table.attr, > + &dev_attr_illuminance0_thresh_falling_value.attr, > + &dev_attr_illuminance0_thresh_rising_value.attr, > + &dev_attr_sampling_frequency.attr, > + &dev_attr_sampling_frequency_available.attr, > + &dev_attr_proximity_thresh_rising_value.attr, > + &dev_attr_proximity_thresh_falling_value.attr, > + &dev_attr_proximity_calibrate.attr, > + &dev_attr_proximity_calibscale_available.attr, > + NULL > +}; > + > +static struct attribute_group tsl2X7X_dev_attr_group_tbl[] = { > + [tsl2571] = { > + .attrs = tsl2571_device_attrs, > + }, > + [tsl2671] = { > + .attrs = tsl2671_device_attrs, > + }, > + [tmd2671] = { > + .attrs = tsl2671_device_attrs, > + }, > + [tsl2771] = { > + .attrs = tsl2771_device_attrs, > + }, > + [tmd2771] = { > + .attrs = tsl2771_device_attrs, > + }, > + [tsl2572] = { > + .attrs = tsl2572_device_attrs, > + }, > + [tsl2672] = { > + .attrs = tsl2672_device_attrs, > + }, > + [tmd2672] = { > + .attrs = tsl2672_device_attrs, > + }, > + [tsl2772] = { > + .attrs = tsl2772_device_attrs, > + }, > + [tmd2772] = { > + .attrs = tsl2772_device_attrs, > + }, > + > +}; > + > +static IIO_DEVICE_ATTR(illuminance_thresh_both_en, > + S_IRUGO | S_IWUSR, > + tsl2x7x_interrupts_en_show, tsl2x7x_interrupts_en_store, 0); > + > +static IIO_DEVICE_ATTR(proximity_thresh_both_en, > + S_IRUGO | S_IWUSR, > + tsl2x7x_prox_interrupt_show, tsl2x7x_prox_interrupt_store, 0); > + > +static struct attribute *tsl2X7X_prox_event_attributes[] = { > + &iio_dev_attr_proximity_thresh_both_en.dev_attr.attr, > + NULL, > +}; > + > +static struct attribute *tsl2X7X_als_event_attributes[] = { > + &iio_dev_attr_illuminance_thresh_both_en.dev_attr.attr, > + NULL, > +}; > + > +static struct attribute *tsl2X7X_proxals_event_attributes[] = { > + &iio_dev_attr_illuminance_thresh_both_en.dev_attr.attr, > + &iio_dev_attr_proximity_thresh_both_en.dev_attr.attr, > + NULL, > +}; The way we have handled this for some similar devices is to just have the two enables done via the iio_chan_spec and chain them both to read / write the same value. (By which I mean the rising enable and falling enable). It slightly clunkier as an interface, but saves code and will ultimately enable them to be accessed by consumer drivers within the kernel (not that we've even started looking at event pass > + > +static struct attribute_group tsl2X7X_event_attr_group_tbl[] = { > + [tsl2571] = { > + .attrs = tsl2X7X_als_event_attributes, > + .name = "events", > + }, > + [tsl2671] = { > + .attrs = tsl2X7X_prox_event_attributes, > + .name = "events", > + }, > + [tmd2671] = { > + .attrs = tsl2X7X_prox_event_attributes, > + .name = "events", > + }, > + [tsl2771] = { > + .attrs = tsl2X7X_proxals_event_attributes, > + .name = "events", > + }, > + [tmd2771] = { > + .attrs = tsl2X7X_proxals_event_attributes, > + .name = "events", > + }, > + > + [tsl2572] = { > + .attrs = tsl2X7X_als_event_attributes, > + .name = "events", > + }, > + [tsl2672] = { > + .attrs = tsl2X7X_prox_event_attributes, > + .name = "events", > + }, > + [tmd2672] = { > + .attrs = tsl2X7X_prox_event_attributes, > + .name = "events", > + }, > + [tsl2772] = { > + .attrs = tsl2X7X_proxals_event_attributes, > + .name = "events", > + }, > + [tmd2772] = { > + .attrs = tsl2X7X_proxals_event_attributes, > + .name = "events", > + } > +}; > + Being fussy, but only one blank line please. > + > +/* Use the default register values to identify the Taos device */ > +static int tsl2x7x_device_id(unsigned char *bufp, int target) > +{ > + switch (target) { > + case tsl2571: > + case tsl2671: > + case tsl2771: > + return ((bufp[TSL2X7X_CHIPID]& 0xf0) == TRITON_ID); > + break; > + case tmd2671: > + case tmd2771: > + return ((bufp[TSL2X7X_CHIPID]& 0xf0) == HALIBUT_ID); > + break; > + case tsl2572: > + case tsl2672: > + case tmd2672: > + case tsl2772: > + case tmd2772: > + return ((bufp[TSL2X7X_CHIPID]& 0xf0) == SWORDFISH_ID); > + break; > + } > + > + return -EINVAL; > +} > + > +static const struct iio_info tsl2X7X_info[] = { > + [tsl2571] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2571], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2571], > + .driver_module = THIS_MODULE, > + }, > + [tsl2671] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2671], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2671], > + .driver_module = THIS_MODULE, > + }, > + [tmd2671] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2671], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2671], > + .driver_module = THIS_MODULE, > + }, > + [tsl2771] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2771], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2771], > + .driver_module = THIS_MODULE, > + }, > + [tmd2771] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2771], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2771], > + .driver_module = THIS_MODULE, > + }, > + [tsl2572] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2572], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2572], > + .driver_module = THIS_MODULE, > + }, > + [tsl2672] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2672], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2672], > + .driver_module = THIS_MODULE, > + }, > + [tmd2672] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2672], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2672], > + .driver_module = THIS_MODULE, > + }, > + [tsl2772] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2772], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2772], > + .driver_module = THIS_MODULE, > + }, > + [tmd2772] = { > + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2772], > + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2772], > + .driver_module = THIS_MODULE, A lot of repeats in here, could you not have fewer entries? Just reuse the enum values in the i2c id table below. > + }, > + > +}; > + > +/* > + * Run-time interrupt handler - depending on whether the device is in ambient > + * light sensing interrupt mode, this handler can queue up > + * a thread, to handle valid interrupts. > + */ > +static irqreturn_t tsl2x7x_event_handler(int irq, void *private) > +{ > + struct iio_dev *indio_dev = private; > + struct tsl2X7X_chip *chip = iio_priv(indio_dev); > + s64 timestamp = iio_get_time_ns(); > + int ret; > + int value; > + > + value = i2c_smbus_read_byte_data(chip->client, > + TSL2X7X_CMD_REG | TSL2X7X_STATUS); > + > + /* What type of interrupt do we need to process */ > + if (value& TSL2X7X_STA_PRX_INTR) { > + tsl2x7x_prox_poll(indio_dev); > + iio_push_event(indio_dev, > + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, > + 0, > + IIO_EV_TYPE_THRESH, > + IIO_EV_DIR_EITHER), > + timestamp); > + } > + > + if (value& TSL2X7X_STA_ALS_INTR) { > + tsl2x7x_get_lux(indio_dev); > + iio_push_event(indio_dev, > + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, > + 0, > + IIO_EV_TYPE_THRESH, > + IIO_EV_DIR_EITHER), > + timestamp); > + } > + /* Clear interrupt now that we have the status */ > + ret = i2c_smbus_write_byte(chip->client, > + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | > + TSL2X7X_CMD_PROXALS_INTCLR); > + if (ret< 0) > + dev_err(&chip->client->dev, > + "Failed to clear irq from event handler. err = %d\n", ret); > + > + return IRQ_HANDLED; > +} > + > +/* > + * Client probe function. > + */ > +static int __devinit tsl2x7x_probe(struct i2c_client *clientp, > + const struct i2c_device_id *id) > +{ > + int i, ret; > + unsigned char buf[TSL2X7X_MAX_DEVICE_REGS]; > + struct iio_dev *indio_dev = > + iio_allocate_device(sizeof(struct tsl2X7X_chip)); Ugly to do non trivial allocation in the variable definitions. Have struct iio_dev *indio_dev; struct tsl2x7x_chip *chip; indio_dev = iio_allocate_device(sizeof(*chip)); if (indio_dev == NULL) { } chip = iio_priv(indio_dev); etc. > + struct tsl2X7X_chip *chip = iio_priv(indio_dev); > + > + if (indio_dev == NULL) { > + ret = -ENOMEM; > + dev_err(&clientp->dev, "iio allocation failed\n"); > + goto fail1; > + } > + > + chip = iio_priv(indio_dev); > + chip->client = clientp; > + i2c_set_clientdata(clientp, indio_dev); > + > + mutex_init(&chip->als_mutex); > + mutex_init(&chip->prox_mutex); > + > + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN; > + > + chip->pdata = clientp->dev.platform_data; > + if (chip->pdata&& chip->pdata->init) > + chip->pdata->init(clientp); > + > + for (i = 0; i< TSL2X7X_MAX_DEVICE_REGS; i++) { > + ret = i2c_smbus_write_byte(clientp, > + (TSL2X7X_CMD_REG | (TSL2X7X_CNTRL + i))); > + if (ret< 0) { > + dev_err(&clientp->dev, "i2c_smbus_write_bytes() to cmd " > + "reg failed in tsl2x7x_probe(), err = %d\n", ret); > + goto fail1; > + } > + ret = i2c_smbus_read_byte(clientp); > + if (ret< 0) { > + dev_err(&clientp->dev, "i2c_smbus_read_byte from " > + "reg failed in tsl2x7x_probe(), err = %d\n", ret); > + > + goto fail1; > + } > + buf[i] = ret; > + } > + > + if ((!tsl2x7x_device_id(buf, id->driver_data)) || > + (tsl2x7x_device_id(buf, id->driver_data) == -EINVAL)) { > + dev_info(&chip->client->dev, "i2c device found but does not match " > + "expected id in tsl2x7x_probe()\n"); > + goto fail1; > + } > + > + chip->id = id->driver_data; > + > + ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); > + if (ret< 0) { > + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg " > + "failed in tsl2x7x_probe(), err = %d\n", ret); > + goto fail1; > + } > + > + indio_dev->info =&tsl2X7X_info[id->driver_data]; > + indio_dev->dev.parent =&clientp->dev; > + indio_dev->modes = INDIO_DIRECT_MODE; > + indio_dev->name = chip->client->name; > + indio_dev->channels = tsl2X7X_channels; > + indio_dev->num_channels = ARRAY_SIZE(tsl2X7X_channels); > + > + ret = iio_device_register(indio_dev); > + if (ret) { > + dev_err(&clientp->dev, "iio registration failed\n"); > + goto fail2; one would normally expect a later failure to result in more needing to be undone, but it appears to be the other way around here. > + } > + > + if (clientp->irq) { > + ret = request_threaded_irq(clientp->irq, > + NULL, > + &tsl2x7x_event_handler, > + IRQF_TRIGGER_RISING | IRQF_ONESHOT, > + "TSL2X7X_event", > + indio_dev); > + if (ret) > + dev_err(&clientp->dev, "irq request failed"); Unwinding after this error? Generally set the irq up and make the iio_device_register pretty much the last thing to happen rather than this way around. Nothing can touch the device before the iio_device_register so it avoids the chance of race conditions without having to be careful! > + } > + > + /* Load up the defaults */ > + tsl2x7x_defaults(chip); > + > + /* Make sure the chip is on */ > + tsl2x7x_chip_on(indio_dev); > + > + dev_info(&clientp->dev, "%s Light sensor found.\n", id->name); > + > + return 0; > + > +fail1: > + if (chip->pdata&& chip->pdata->teardown) > + chip->pdata->teardown(clientp); > + iio_free_device(indio_dev); > + > +fail2: > + return ret; loose the bonus blank line. > + > +} > + > + > +static int tsl2x7x_suspend(struct device *dev) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); standardize the naming please. indio_dev preferably but consistency is most important. > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + > + int ret = 0; > + > + /* Blocks if work is active */ > + cancel_work_sync(&chip->work_thresh); > + > + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { > + ret = tsl2x7x_chip_off(dev_info); > + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; > + } > + > + if (chip->pdata&& chip->pdata->platform_power) { > + pm_message_t pmm = {PM_EVENT_SUSPEND}; > + chip->pdata->platform_power(dev, pmm); > + } > + > + return ret; > +} > + > +static int tsl2x7x_resume(struct device *dev) > +{ > + struct iio_dev *dev_info = dev_get_drvdata(dev); > + struct tsl2X7X_chip *chip = iio_priv(dev_info); > + int ret = 0; > + > + if (chip->pdata&& chip->pdata->platform_power) { > + pm_message_t pmm = {PM_EVENT_RESUME}; > + chip->pdata->platform_power(dev, pmm); > + } > + > + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED) > + ret = tsl2x7x_chip_on(dev_info); > + > + return ret; > +} > + > +static int __devexit tsl2x7x_remove(struct i2c_client *client) > +{ > + struct iio_dev *indio_dev = i2c_get_clientdata(client); > + struct tsl2X7X_chip *chip = i2c_get_clientdata(client); Err, the two lines above seem a little implausible. > + > + tsl2x7x_chip_off(indio_dev); > + > + if (client->irq) > + free_irq(client->irq, chip->client->name); > + > + flush_scheduled_work(); > + > + iio_device_unregister(chip->iio_dev); or use the indio_dev pointer you already have. There is rarely a reason to have a pointer to the iio_dev in the driver private bit. > + kfree(chip); > + > + if (chip->pdata&& chip->pdata->teardown) > + chip->pdata->teardown(client); > + > + return 0; > +} > + > +static struct i2c_device_id tsl2x7x_idtable[] = { I'm guessing there is a magic ordering here, but might be nicer just to go with alphabetical order.. > + { "tsl2571", tsl2571 }, > + { "tsl2671", tsl2671 }, > + { "tmd2671", tmd2671 }, > + { "tsl2771", tsl2771 }, > + { "tmd2771", tmd2771 }, > + { "tsl2572", tsl2572 }, > + { "tsl2672", tsl2672 }, > + { "tmd2672", tmd2672 }, > + { "tsl2772", tsl2772 }, > + { "tmd2772", tmd2772 }, > + {} > +}; > + > +MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable); > + > +static const struct dev_pm_ops tsl2x7x_pm_ops = { > + .suspend = tsl2x7x_suspend, > + .resume = tsl2x7x_resume, > +}; > + > +/* Driver definition */ > +static struct i2c_driver tsl2x7x_driver = { > + .driver = { > + .name = "tsl2X7X", > + .pm =&tsl2x7x_pm_ops, > + > + }, > + .id_table = tsl2x7x_idtable, > + .probe = tsl2x7x_probe, > + .remove = __devexit_p(tsl2x7x_remove), > +}; > + > +static int __init tsl2x7x_init(void) > +{ > + return i2c_add_driver(&tsl2x7x_driver); > +} > + > +static void __exit tsl2x7x_exit(void) > +{ > + i2c_del_driver(&tsl2x7x_driver); > +} > + > +module_init(tsl2x7x_init); > +module_exit(tsl2x7x_exit); Some nice new macros to handle this boiler plate. see module_i2c_driver in include/linux/i2c.h > + > +MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>"); > +MODULE_DESCRIPTION("TAOS tsl2X7X ambient light sensor driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/staging/iio/light/tsl2x7x_core.h b/drivers/staging/iio/light/tsl2x7x_core.h > new file mode 100644 > index 0000000..9a64412 > --- /dev/null > +++ b/drivers/staging/iio/light/tsl2x7x_core.h > @@ -0,0 +1,138 @@ > +/* > + * Device driver for monitoring ambient light intensity (lux) > + * and proximity (prox) within the TAOS TSL2X7X family of devices. > + * > + * Copyright (c) 2012, TAOS Corporation. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along > + * with this program; if not, write to the Free Software Foundation, Inc., > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. > + */ > + > +#ifndef __TSL2X7X_H > +#define __TSL2X7X_H > +#include<linux/pm.h> > + > +#include "../iio.h" loose this header and just forward declare the pointer. e.g. struct iio_dev; > + > +/* TAOS Register definitions - note: > + * depending on device, some of these register are not used and the > + * register address is benign. > + */ > +/* 2X7X register offsets */ > +#define TSL2X7X_MAX_DEVICE_REGS 32 > +#define TSL2X7X_REG_MAX 16 > + > +/* Device Registers and Masks */ > +#define TSL2X7X_CNTRL 0x00 > +#define TSL2X7X_ALS_TIME 0X01 > +#define TSL2X7X_PRX_TIME 0x02 > +#define TSL2X7X_WAIT_TIME 0x03 > +#define TSL2X7X_ALS_MINTHRESHLO 0X04 > +#define TSL2X7X_ALS_MINTHRESHHI 0X05 > +#define TSL2X7X_ALS_MAXTHRESHLO 0X06 > +#define TSL2X7X_ALS_MAXTHRESHHI 0X07 > +#define TSL2X7X_PRX_MINTHRESHLO 0X08 > +#define TSL2X7X_PRX_MINTHRESHHI 0X09 > +#define TSL2X7X_PRX_MAXTHRESHLO 0X0A > +#define TSL2X7X_PRX_MAXTHRESHHI 0X0B > +#define TSL2X7X_PERSISTENCE 0x0C > +#define TSL2X7X_PRX_CONFIG 0x0D > +#define TSL2X7X_PRX_COUNT 0x0E > +#define TSL2X7X_GAIN 0x0F > +#define TSL2X7X_NOTUSED 0x10 > +#define TSL2X7X_REVID 0x11 > +#define TSL2X7X_CHIPID 0x12 > +#define TSL2X7X_STATUS 0x13 > +#define TSL2X7X_ALS_CHAN0LO 0x14 > +#define TSL2X7X_ALS_CHAN0HI 0x15 > +#define TSL2X7X_ALS_CHAN1LO 0x16 > +#define TSL2X7X_ALS_CHAN1HI 0x17 > +#define TSL2X7X_PRX_LO 0x18 > +#define TSL2X7X_PRX_HI 0x19 > + > +/* tsl2X7X cmd reg masks */ > +#define TSL2X7X_CMD_REG 0x80 > +#define TSL2X7X_CMD_SPL_FN 0x60 > + > +#define TSL2X7X_CMD_PROX_INT_CLR 0X05 > +#define TSL2X7X_CMD_ALS_INT_CLR 0x06 > +#define CMD_PROXALS_INT_CLR 0X07 > + > +/* tsl2X7X cntrl reg masks */ > +#define TSL2X7X_CNTL_ADC_ENBL 0x02 > +#define TSL2X7X_CNTL_PWR_ON 0x01 > + > +/* tsl2X7X status reg masks */ > +#define TSL2X7X_STA_ADC_VALID 0x01 > +#define TSL2X7X_STA_PRX_VALID 0x02 > +#define TSL2X7X_STA_ADC_PRX_VALID 0x03 > +#define TSL2X7X_STA_ALS_INTR 0x10 > +#define TSL2X7X_STA_ADC_INTR 0x10 > +#define TSL2X7X_STA_PRX_INTR 0x20 > + > +#define TSL2X7X_STA_ADC_INTR 0x10 > + > +/* tsl2X7X cntrl reg masks */ > +#define CNTL_REG_CLEAR 0x00 > +#define CNTL_PROX_INT_ENBL 0X20 > +#define CNTL_ALS_INT_ENBL 0X10 > +#define TSL2X7X_CNTL_WAIT_TMR_ENBL 0X08 > +#define CNTL_PROX_DET_ENBL 0X04 > +#define CNTL_ADC_ENBL 0x02 > +#define TSL2X7X_CNTL_PWRON 0x01 > +#define CNTL_ALSPON_ENBL 0x03 > +#define CNTL_INTALSPON_ENBL 0x13 > +#define CNTL_PROXPON_ENBL 0x0F > +#define CNTL_INTPROXPON_ENBL 0x2F > +#define TSL2X7X_CMD_PROXALS_INTCLR 0X07 > + Chances of a clash on these definitions is extremely high, Stick a prefix in front of them to avoid that issue. > +/*Prox diode to use */ > +#define DIODE0 0x10 > +#define DIODE1 0x20 > +#define DIODE_BOTH 0x30 > + > +/* LED Power */ > +#define mA100 0x00 > +#define mA50 0x40 > +#define mA25 0x80 > +#define mA13 0xD0 > + > +/* Max number of segments allowable in LUX table */ > +#define MAX_TABLE_SIZE 9 > +#define MAX_DEFAULT_TABLE_BYTES (sizeof(int) * MAX_TABLE_SIZE) > + > +struct tsl2x7x_lux { > + unsigned int ratio; > + unsigned int ch0; > + unsigned int ch1; > +}; > + > + Kernel doc for comments would be preferable. Can you also give a description of what actually tends to occur in these callbacks? I can't help feeling there are rather more of them than we'd normally expect. > +/* struct tsl2x7x_platform_data - Assume all varients will have this */ > +struct tsl2X7X_platform_data { > + int (*platform_power)(struct device *dev, pm_message_t); > + /* The following callback gets called when the TSL2772 is powered on */ > + int (*power_on) (struct iio_dev *indio_dev); > + /* The following callback gets called when the TSL2772 is powered off */ > + int (*power_off) (struct i2c_client *dev); > + /* The following callback gets called when the driver is added */ > + int (*init) (struct i2c_client *dev); > + /* The following callback gets called when the driver is removed */ > + int (*teardown) (struct i2c_client *dev); > + /* These are the device specific glass coefficents used to > + * calculate Lux */ > + struct tsl2x7x_lux platform_lux_table[MAX_TABLE_SIZE]; > +}; > + > +#endif /* __TSL2X7X_H */ > -- > ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH V1] TAOS tsl2x7x 2012-02-13 15:19 ` Jonathan Cameron @ 2012-02-13 15:28 ` Jonathan Cameron 0 siblings, 0 replies; 3+ messages in thread From: Jonathan Cameron @ 2012-02-13 15:28 UTC (permalink / raw) To: Jon Brenner; +Cc: Jonathan Cameron, linux-kernel, linux-iio On 2/13/2012 3:19 PM, Jonathan Cameron wrote: > On 2/10/2012 7:06 PM, Jon Brenner wrote: >> TAOS device driver for tsl/tmd 2771 and 2772 device families (inc all >> variants). >> >> Signed-off-by: Jon Brenner<jbrenner@taosinc.com> > Hi Jon, > Not enough coffee.. Reasonably clean. ... > Good to see another driver from you. Reasonably keen but couple of > medium sized issues > a) Use iio_chan_spec and callbacks in iio_info structure where > possible. Propose additional > elements where they make sense (such as your integration time). > b) Documentation should be slotted in relevant places in more general > files. > c) I'm unconvinced the calibration stuff should be in kernel. > > Thanks, > > Jonathan >> >> --- >> .../iio/Documentation/sysfs-bus-iio-light-tsl2x7x | 71 + >> drivers/staging/iio/light/Kconfig | 11 + >> drivers/staging/iio/light/Makefile | 1 + >> drivers/staging/iio/light/tsl2x7x_core.c | 2053 >> ++++++++++++++++++++ >> drivers/staging/iio/light/tsl2x7x_core.h | 138 ++ >> 5 files changed, 2274 insertions(+), 0 deletions(-) >> >> diff --git >> a/drivers/staging/iio/Documentation/sysfs-bus-iio-light-tsl2x7x >> b/drivers/staging/iio/Documentation/sysfs-bus-iio-light-tsl2x7x >> new file mode 100644 >> index 0000000..f1bb5f5 >> --- /dev/null >> +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light-tsl2x7x >> @@ -0,0 +1,71 @@ > Most of these are fairly general purpose so should be sysfs-bus-iio or > sysfs-bus-iio-light. > Some are also shared with the tsl2583 doc so maybe move those into the > light one. > > Generally if the last bit (after the channel type) is restricted to > the actual device then > it wants to be in this file. > If it's restricted to the class (light / proximity) then it wants to be > in sysfs-bus-iio-light or sysfs-bus-iio-proximity > If like proximity_raw or the thresh_value ones then it wants to be > in sysfs-bus-iio. > > Please do fix any cases where this isn't currently the case. Our > documentation outside the top > level file is far from well written or organized. > >> +What: /sys/bus/iio/devices/device[n]/lux_table >> +KernelVersion: 2.6.37 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + This property gets/sets the table of coefficients >> + used in calculating illuminance in lux. >> + >> +What: /sys/bus/iio/devices/device[n]/illuminance0_calibrate >> +KernelVersion: 2.6.37 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + This property causes an internal calibration of the als gain >> trim >> + value which is later used in calculating illuminance in lux. >> + >> +What: >> /sys/bus/iio/devices/device[n]/illuminance0_thresh_falling_value >> +KernelVersion: 3.3-rc1 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + Low (falling) trigger point for the internal ALS comparison >> + function for interrupt generation. > This one just needs adding to sysfs-bus-iio. >> + >> +What: >> /sys/bus/iio/devices/device[n]/illuminance0_thresh_rising_value >> +KernelVersion: 3.3-rc1 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + high (rising) trigger point for the internal ALS comparison >> + function for interrupt generation. >> + >> +What: /sys/bus/iio/devices/device[n]/illuminance0_both_raw >> +KernelVersion: 3.3-rc1 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + Simultainious ALS channel 1 and channel 2 data represented as >> + a 32 bit integer. > err. previously the both has referred to the light frequencies > covered. Please don't do what you > describe here. If you really need to be sure they are pared then you > want to use the buffered > infrastructure not sysfs. > >> + >> +What: /sys/bus/iio/devices/device[n]/proximity_calibrate >> +KernelVersion: 3.3-rc1 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + Causes an recalculation and adjustment to the >> + proximity_thresh_rising_value. >> + >> +What: >> /sys/bus/iio/devices/device[n]/proximity_thresh_falling_value >> +KernelVersion: 3.3-rc1 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + Low (falling) trigger point for the internal proximity >> comparison >> + function for interrupt generation. >> + > Again, standard form so add to sysfs-bus-iio. >> +What: >> /sys/bus/iio/devices/device[n]/proximity_thresh_rising_value >> +KernelVersion: 3.3-rc1 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + high (rising) trigger point for the internal proximity >> comparison >> + function for interrupt generation. >> + >> +What: /sys/bus/iio/devices/device[n]/proximity_calibscale >> +KernelVersion: 3.3-rc1 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + Hardware or software applied calibration scale factor assumed >> + to account for attenuation due to industrial design (glass >> + filters or aperture holes). >> + > All of these are standard so add to sysfs-bus-iio lists for calibscale >> +What: /sys/bus/iio/devices/device[n]/proximity_raw >> +KernelVersion: 3.3-rc1 >> +Contact: linux-iio@vger.kernel.org >> +Description: >> + State of proximity detection based on the >> + proximity_thresh_rising_value. > If you wouldn't mind can you lift he proximity documentation out of > sysfs-bus-iio-ilght into sysfs-bus-iio > then we can take all the standard definitions without adding them yet > again. (as a separate patch). > > I'm still kind of regretting ever introducing multiple sysfs > documentatino files. >> + >> diff --git a/drivers/staging/iio/light/Kconfig >> b/drivers/staging/iio/light/Kconfig >> index e7e9159..29de333 100644 >> --- a/drivers/staging/iio/light/Kconfig >> +++ b/drivers/staging/iio/light/Kconfig >> @@ -31,4 +31,15 @@ config TSL2583 >> Provides support for the TAOS tsl2580, tsl2581 and tsl2583 >> devices. >> Access ALS data via iio, sysfs. >> >> + This driver can also be built as a module. If so, the module >> + will be called tsl2583. > errr. This change to a comment about a completely different driver > should not be in this patch. >> + >> +config TSL2x7x >> + tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and >> proximity sensors" >> + depends on I2C >> + help >> + Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, >> tsl2572, tsl2672, >> + tmd2672, tsl2772, tmd2772 devices. >> + Provides iio_events and direct access via sysfs. >> + >> endmenu >> diff --git a/drivers/staging/iio/light/Makefile >> b/drivers/staging/iio/light/Makefile >> index 3011fbf..ff12c4b 100644 >> --- a/drivers/staging/iio/light/Makefile >> +++ b/drivers/staging/iio/light/Makefile >> @@ -5,3 +5,4 @@ >> obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o >> obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o >> obj-$(CONFIG_TSL2583) += tsl2583.o >> +obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o >> diff --git a/drivers/staging/iio/light/tsl2x7x_core.c >> b/drivers/staging/iio/light/tsl2x7x_core.c >> new file mode 100644 >> index 0000000..671f476 >> --- /dev/null >> +++ b/drivers/staging/iio/light/tsl2x7x_core.c >> @@ -0,0 +1,2053 @@ >> +/* >> + * Device driver for monitoring ambient light intensity in (lux) >> + * and proximity detection (prox) within the TAOS TSL2X7X family of >> devices. >> + * >> + * Copyright (c) 2012, TAOS Corporation. >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> but WITHOUT >> + * ANY WARRANTY; without even the implied warranty of >> MERCHANTABILITY or >> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public >> License for >> + * more details. >> + * >> + * You should have received a copy of the GNU General Public License >> along >> + * with this program; if not, write to the Free Software Foundation, >> Inc., >> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. >> + */ >> + >> +#include<linux/kernel.h> >> +#include<linux/i2c.h> >> +#include<linux/errno.h> >> +#include<linux/delay.h> >> +#include<linux/string.h> >> +#include<linux/mutex.h> >> +#include<linux/unistd.h> >> +#include<linux/interrupt.h> >> +#include<linux/platform_device.h> >> +#include<linux/input.h> >> +#include<linux/slab.h> >> +#include<linux/pm.h> >> +#include<linux/module.h> >> +#include<linux/version.h> >> + >> +#include<linux/cdev.h> >> +#include<linux/stat.h> >> +#include<linux/module.h> >> +#include "tsl2x7x_core.h" >> +#include "../events.h" >> +#include "../buffer.h" >> +#include "../iio.h" >> +#include "../sysfs.h" >> + >> +/* Cal defs*/ >> +#define PROX_STAT_CAL 0 >> +#define PROX_STAT_SAMP 1 >> +#define MAX_SAMPLES_CAL 200 >> + >> +/* TSL2X7X Device ID */ >> +#define TRITON_ID 0x00 >> +#define SWORDFISH_ID 0x30 >> +#define HALIBUT_ID 0x20 >> + >> +/* Lux calculation constants */ >> +#define TSL2X7X_LUX_CALC_OVER_FLOW 65535 >> + >> +/* TAOS txx2x7x Device family members */ >> +enum { >> + tsl2571, >> + tsl2671, >> + tmd2671, >> + tsl2771, >> + tmd2771, >> + tsl2572, >> + tsl2672, >> + tmd2672, >> + tsl2772, >> + tmd2772 >> +}; >> + >> +enum { >> + TSL2X7X_CHIP_UNKNOWN = 0, >> + TSL2X7X_CHIP_WORKING = 1, >> + TSL2X7X_CHIP_SUSPENDED = 2 >> +}; >> + >> +/* Per-device data */ >> +struct tsl2x7x_als_info { >> + u16 als_ch0; >> + u16 als_ch1; >> + u16 lux; >> +}; >> + >> +/* proximity data */ >> +struct tsl2x7x_prox_info { >> + u16 prox_data; >> + int prox_event; >> +}; >> + >> +struct prox_stat { >> + u16 min; >> + u16 max; >> + u16 mean; >> + unsigned long stddev; >> +}; >> + >> +struct tsl2x7x_settings { >> + int als_time; >> + int als_gain; >> + int als_gain_trim; >> + int wait_time; >> + int prx_time; >> + int prox_gain; >> + int prox_config; >> + int als_cal_target; >> + u8 interrupts_en; >> + u8 als_persistence; >> + int als_thresh_low; >> + int als_thresh_high; >> + int prox_thres_low; >> + int prox_thres_high; >> + int prox_pulse_count; >> + int prox_max_samples_cal;/* for calibration mode*/ >> + >> +}; >> + >> +struct tsl2X7X_chip_info { >> + struct iio_chan_spec channel[0]; >> + const struct iio_info *info; >> +}; > err. what is channel[0] for? Please do the iio_chan_spec stuff fully. >> + >> +struct tsl2X7X_chip { >> + kernel_ulong_t id; >> + struct mutex prox_mutex; >> + struct mutex als_mutex; >> + struct i2c_client *client; >> + struct iio_dev *iio_dev; >> + struct tsl2x7x_prox_info prox_cur_info; >> + struct tsl2x7x_als_info als_cur_info; >> + struct tsl2x7x_settings tsl2x7x_settings; >> + struct tsl2X7X_platform_data *pdata; >> + int als_time_scale; >> + int als_saturation; >> + int tsl2x7x_chip_status; >> + u8 tsl2x7x_config[TSL2X7X_REG_MAX]; >> + bool init_done; >> + struct work_struct work_thresh; >> + s64 event_timestamp; >> + /* This structure is intentionally large to accommodate >> + * updates via sysfs. */ >> + /* Sized to 9 = max 8 segments + 1 termination segment */ >> + /* Assumption is one and only one type of glass used */ >> + struct tsl2x7x_lux tsl2x7x_device_lux[MAX_TABLE_SIZE]; >> +}; >> + >> +/* Different devices require different coefficents */ >> +static const struct tsl2x7x_lux tsl2x71_lux_table[] = { >> + { 14461, 611, 1211 }, >> + { 18540, 352, 623 }, >> + { 0, 0, 0 }, >> +}; >> + >> +static const struct tsl2x7x_lux tmd2x71_lux_table[] = { >> + { 11635, 115, 256 }, >> + { 15536, 87, 179 }, >> + { 0, 0, 0 }, >> +}; >> + >> +static const struct tsl2x7x_lux tsl2x72_lux_table[] = { >> + { 14013, 466, 917 }, >> + { 18222, 310, 552 }, >> + { 0, 0, 0 }, >> +}; >> + >> +static const struct tsl2x7x_lux tmd2x72_lux_table[] = { >> + { 13218, 130, 262 }, >> + { 17592, 92, 169 }, >> + { 0, 0, 0 }, >> +}; >> + >> +static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = { >> + [tsl2571] = tsl2x71_lux_table, >> + [tsl2671] = tsl2x71_lux_table, >> + [tmd2671] = tmd2x71_lux_table, >> + [tsl2771] = tsl2x71_lux_table, >> + [tmd2771] = tmd2x71_lux_table, >> + [tsl2572] = tsl2x72_lux_table, >> + [tsl2672] = tsl2x72_lux_table, > Check your spacing vs tabs. >> + [tmd2672] = tmd2x72_lux_table, >> + [tsl2772] = tsl2x72_lux_table, >> + [tmd2772] = tmd2x72_lux_table, >> +}; >> + >> +struct als_gainadj { >> + s16 ch0; >> + s16 ch1; >> +}; >> + >> +/* Used to validate the ALS gain selection index */ >> +static const struct als_gainadj tsl2X7X_als_gainadj[] = { >> + { 1, 1 }, >> + { 8, 8 }, >> + { 16, 16 }, >> + { 120, 120 } >> +}; > This is a somewhat novel structure.... Any real point in the two > columns? >> + >> + >> +/* Not using channels */ >> +static const struct iio_chan_spec tsl2X7X_channels[] = {}; >> + >> +/* >> + * Read a number of bytes starting at register (reg) location. >> + * Return 0, or i2c_smbus_write_byte ERROR code. >> + */ >> +static int >> +tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val, >> unsigned int len) >> +{ >> + int ret; >> + int i; >> + >> + for (i = 0; i< len; i++) { > Just to check, does this correspond to > i2c_smbus_read_byte_data(client, (TSL2X7X_CMD_REG | REG))? > Also, a quick look makes me think you only ever use this for one byte > at a time... > >> + /* select register to write */ >> + ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg)); >> + if (ret< 0) { >> + dev_err(&client->dev, "tsl2x7x_i2c_read failed to write" >> + " register %x\n", reg); >> + return ret; >> + } >> + /* read the data */ >> + *val = i2c_smbus_read_byte(client); >> + val++; >> + reg++; >> + } >> + return 0; >> +} >> + >> +/* > Kernel doc please. >> + * Reads and calculates current lux value. >> + * The raw ch0 and ch1 values of the ambient light sensed in the last >> + * integration cycle are read from the device. >> + * Time scale factor array values are adjusted based on the >> integration time. >> + * The raw values are multiplied by a scale factor, and device gain >> is obtained >> + * using gain index. Limit checks are done next, then the ratio of a >> multiple >> + * of ch1 value, to the ch0 value, is calculated. The array >> tsl2x7x_device_lux[] >> + * declared above is then scanned to find the first ratio value that >> is just >> + * above the ratio we just calculated. The ch0 and ch1 multiplier >> constants in >> + * the array are then used along with the time scale factor array >> values, to >> + * calculate the lux. >> + */ >> +static int tsl2x7x_get_lux(struct iio_dev *indio_dev) >> +{ >> + u16 ch0, ch1; /* separated ch0/ch1 data from device */ >> + u32 lux; /* raw lux calculated from device data */ >> + u64 lux64; >> + u32 ratio; >> +#pragma pack(4) > ? that needs some explanation... >> + u8 buf[4]; >> + struct tsl2x7x_lux *p; >> + struct tsl2X7X_chip *chip = iio_priv(indio_dev); >> + int i, ret; >> + u32 ch0lux = 0; >> + u32 ch1lux = 0; >> + > as below, I find these try locks rather suspicious. Please justify. >> + if (mutex_trylock(&chip->als_mutex) == 0) { >> + dev_info(&chip->client->dev, "tsl2x7x_get_lux device is >> busy\n"); >> + return chip->als_cur_info.lux; /* busy, so return LAST VALUE */ >> + } >> + >> + if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) { >> + /* device is not enabled */ >> + dev_err(&chip->client->dev, "tsl2x7x_get_lux device is not >> enabled\n"); >> + ret = -EBUSY ; >> + goto out_unlock; >> + } >> + >> + ret = tsl2x7x_i2c_read(chip->client, >> + (TSL2X7X_CMD_REG | TSL2X7X_STATUS),&buf[0], 1); >> + if (ret< 0) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_get_lux failed to read CMD_REG\n"); >> + goto out_unlock; >> + } >> + /* is data new& valid */ >> + if (!(buf[0]& TSL2X7X_STA_ADC_VALID)) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_get_lux data not valid yet\n"); >> + ret = chip->als_cur_info.lux; /* return LAST VALUE */ >> + goto out_unlock; >> + } >> + >> + for (i = 0; i< 4; i++) { >> + ret = tsl2x7x_i2c_read(chip->client, >> + (TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i)), >> + &buf[i], 1); >> + if (ret< 0) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_get_lux failed to read" >> + " ret: %x\n", ret); >> + goto out_unlock; >> + } >> + } >> + >> + /* clear status, really interrupt status ( are off), >> + but we use the bit anyway */ >> + ret = i2c_smbus_write_byte(chip->client, >> + (TSL2X7X_CMD_REG | >> + TSL2X7X_CMD_SPL_FN | >> + TSL2X7X_CMD_ALS_INT_CLR)); >> + >> + if (ret< 0) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_i2c_write_command failed in tsl2x7x_get_lux, err = >> %d\n", >> + ret); >> + goto out_unlock; /* have no data, so return failure */ >> + } >> + >> + /* extract ALS/lux data */ >> + ch0 = le16_to_cpup((const __le16 *)&buf[0]); >> + ch1 = le16_to_cpup((const __le16 *)&buf[2]); >> + >> + chip->als_cur_info.als_ch0 = ch0; >> + chip->als_cur_info.als_ch1 = ch1; >> + >> + if ((ch0>= chip->als_saturation) || (ch1>= chip->als_saturation)) >> + goto return_max; >> + >> + if (ch0 == 0) { >> + /* have no data, so return LAST VALUE */ >> + ret = chip->als_cur_info.lux = 0; >> + goto out_unlock; >> + } >> + /* calculate ratio */ >> + ratio = (ch1<< 15) / ch0; >> + /* convert to unscaled lux using the pointer to the table */ >> + for (p = (struct tsl2x7x_lux *) chip->tsl2x7x_device_lux; >> + p->ratio != 0&& p->ratio< ratio; p++) > stray semi colon. >> + ; >> + >> + if (p->ratio == 0) { >> + lux = 0; >> + } else { >> + ch0lux = ((ch0 * p->ch0) + >> + (tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch0>> >> 1)) >> + / tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch0; >> + >> + ch1lux = ((ch1 * p->ch1) + >> + (tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch1>> >> 1)) >> + / tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch1; >> + >> + lux = ch0lux - ch1lux; >> + } >> + >> + /* note: lux is 31 bit max at this point */ >> + if (ch1lux> ch0lux) { >> + dev_dbg(&chip->client->dev, "No Data - Return last value\n"); >> + ret = chip->als_cur_info.lux = 0; >> + goto out_unlock; >> + } >> + >> + /* adjust for active time scale */ >> + if (chip->als_time_scale == 0) >> + lux = 0; >> + else >> + lux = (lux + (chip->als_time_scale>> 1)) / >> + chip->als_time_scale; >> + >> + /* adjust for active gain scale >> + * The tsl2x7x_device_lux tables have a factor of 256 built-in. >> + * User-specified gain provides a multiplier. >> + * Apply user-specified gain before shifting right to retain >> precision. >> + * Use 64 bits to avoid overflow on multiplication. >> + * Then go back to 32 bits before division to avoid using >> div_u64(). >> + */ >> + lux64 = lux; >> + lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim; >> + lux64>>= 8; >> + lux = lux64; >> + lux = (lux + 500) / 1000; >> + >> + if (lux> TSL2X7X_LUX_CALC_OVER_FLOW) { /* check for overflow */ >> +return_max: >> + lux = TSL2X7X_LUX_CALC_OVER_FLOW; >> + } >> + >> + /* Update the structure with the latest VALID lux. */ >> + chip->als_cur_info.lux = lux; >> + ret = lux; >> + >> +out_unlock: >> + mutex_unlock(&chip->als_mutex); >> + return ret; >> + >> +} >> + >> +/* >> + * Proximity poll function - if valid data is available, read and >> form the ch0 >> + * and prox data values, check for limits on the ch0 value, and >> check the prox >> + * data against the current thresholds, to set the event status >> accordingly. >> + */ >> +static int tsl2x7x_prox_poll(struct iio_dev *indio_dev) >> +{ >> +#define CONSECUTIVE_RETRIES 50 >> + >> + int i; >> + int ret; >> + u8 status; >> + u8 chdata[2]; >> + int err_cnt; >> + struct tsl2X7X_chip *chip = iio_priv(indio_dev); >> + >> + if (mutex_trylock(&chip->prox_mutex) == 0) { >> + dev_err(&chip->client->dev, "Can't get prox mutex\n"); >> + return -EBUSY; >> + } > Trylocks always need an explanation as far as I am concerned. why not > wait? >> + >> + err_cnt = 0; >> + >> +try_again: >> + ret = tsl2x7x_i2c_read(chip->client, >> + (TSL2X7X_CMD_REG | TSL2X7X_STATUS),&status, 1); >> + if (ret< 0) { >> + dev_err(&chip->client->dev, >> + "Read regs failed in tsl2x7x_prox_poll() - A\n"); >> + mutex_unlock(&chip->prox_mutex); >> + return ret; >> + } >> + >> + /*Prox interrupt asserted*/ >> + if (((chip->tsl2x7x_settings.interrupts_en<< 4) >> + & CNTL_PROX_INT_ENBL)) { >> + if (!(status& TSL2X7X_STA_ADC_VALID)) { > I've not read the datasheet but this seems unusual. You get an > interrupt but the > value isn't valid? >> + err_cnt++; >> + if (err_cnt> CONSECUTIVE_RETRIES) { >> + mutex_unlock(&chip->prox_mutex); >> + dev_err(&chip->client->dev, >> + "Consec. retries exceeded\n"); >> + return chip->prox_cur_info.prox_event; >> + } >> + goto try_again; >> + } >> + } >> + >> + for (i = 0; i< 2; i++) { >> + ret = tsl2x7x_i2c_read(chip->client, >> + (TSL2X7X_CMD_REG | >> + (TSL2X7X_PRX_LO + i)),&chdata[i], 1); >> + if (ret< 0) { > Errors like this are extremely unlikely (I hope) so I'd drop the > message. Also use a goto > and have the mutex_unlock in only one place as it's easier to read. >> + dev_err(&chip->client->dev, >> + "Read regs failed in tsl2x7x_prox_poll() - B\n"); >> + mutex_unlock(&chip->prox_mutex); >> + return ret; >> + } >> + } >> + >> + chip->prox_cur_info.prox_data = (chdata[1]<<8)|chdata[0]; >> + >> + if (chip->prox_cur_info.prox_data>= >> + chip->tsl2x7x_settings.prox_thres_high) >> + chip->prox_cur_info.prox_event = 1; >> + else >> + chip->prox_cur_info.prox_event = 0; > use chip->proc_cur_info.prox_event = chip->prox_cur_info.prox_data >= > chip->tsl2x7x_settings.prox_thresh_high; >> + >> + mutex_unlock(&chip->prox_mutex); >> + return chip->prox_cur_info.prox_event; >> +} >> + >> +/* >> + * Provides initial operational parameter defaults. >> + * These defaults may be changed through the device's sysfs files. >> + */ > Have a > const static struct tsl2x7x_settings tsl2x7x_defaults = > { > .als_time = 200, > ... > }; > then memcpy it into place as necessary. >> +static void tsl2x7x_defaults(struct tsl2X7X_chip *chip) >> +{ >> + /* Operational parameters */ >> + chip->tsl2x7x_settings.als_time = 200; >> + /* must be a multiple of 50mS */ >> + chip->tsl2x7x_settings.als_gain = 0; >> + /* this is actually an index into the gain table */ >> + chip->tsl2x7x_settings.prx_time = 0xfe; /*5.4 mS */ >> + /* 2.7ms prox integration time - decrease to increase time */ >> + /* decreases in 2.7 ms intervals */ >> + chip->tsl2x7x_settings.prox_gain = 1; >> + /* these are bits 3:2 of reg 0x0f: 0=x1,1=x2,2=x4,3=x8 */ >> + /* assume clear glass as default */ >> + chip->tsl2x7x_settings.wait_time = 245; >> + /* Time between PRX and ALS cycles -decrease to increase time */ >> + /* decreases in 2.7 ms intervals */ >> + chip->tsl2x7x_settings.prox_config = 0; >> + /* Prox configuration filters */ >> + chip->tsl2x7x_settings.als_gain_trim = 1000; >> + /* default gain trim to account for aperture effects */ >> + chip->tsl2x7x_settings.als_cal_target = 150; >> + /* Known external ALS reading used for calibration */ >> + chip->tsl2x7x_settings.als_thresh_low = 200; >> + /* CH0 'low' count to trigger interrupt */ >> + chip->tsl2x7x_settings.als_thresh_high = 256; >> + /* CH0 'high' count to trigger interrupt */ >> + chip->tsl2x7x_settings.als_persistence = 0xFF; >> + /* Number of 'out of limits' ADC readings PRX/ALS*/ >> + chip->tsl2x7x_settings.interrupts_en = 0x00; >> + /* Default interrupt(s) enabled. >> + * 0x00 = none, 0x10 = als, 0x20 = prx 0x30 = bth */ >> + chip->tsl2x7x_settings.prox_thres_low = 0; >> + chip->tsl2x7x_settings.prox_thres_high = 512; >> + /*default threshold (adjust either manually or with cal routine*/ >> + chip->tsl2x7x_settings.prox_max_samples_cal = 30; >> + chip->tsl2x7x_settings.prox_pulse_count = 8; >> + >> + /* Load up the lux table. Can be changed later via ABI */ >> + if (chip->pdata&& chip->pdata->platform_lux_table[0].ratio != 0) >> + memcpy(chip->tsl2x7x_device_lux, >> + chip->pdata->platform_lux_table, >> + sizeof(chip->pdata->platform_lux_table)); >> + else >> + memcpy(chip->tsl2x7x_device_lux, >> + (struct tsl2x7x_lux >> *)tsl2x7x_default_lux_table_group[chip->id], >> + MAX_DEFAULT_TABLE_BYTES); >> + >> +} >> + > As I've stated below, you really need to justify why we have > calibration in the kernel rather > than userspace.. >> +/* >> + * Obtain single reading and calculate the als_gain_trim >> + * (later used to derive actual lux). >> + * Return updated gain_trim value. >> + */ >> +static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev) >> +{ >> + struct tsl2X7X_chip *chip = iio_priv(indio_dev); >> + u8 reg_val; >> + int gain_trim_val; >> + int ret; >> + int lux_val; >> + >> + ret = i2c_smbus_write_byte(chip->client, >> + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); >> + if (ret< 0) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_als_calibrate failed to write CNTRL register, >> ret=%d\n", >> + ret); >> + return ret; >> + } >> + >> + reg_val = i2c_smbus_read_byte(chip->client); >> + if ((reg_val& (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) >> + != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_als_calibrate failed: ADC not enabled\n"); >> + return -1; >> + } >> + >> + ret = i2c_smbus_write_byte(chip->client, >> + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL)); >> + if (ret< 0) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_als_calibrate failed to write ctrl reg: ret=%d\n", >> + ret); >> + return ret; >> + } >> + reg_val = i2c_smbus_read_byte(chip->client); >> + >> + if ((reg_val& TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_als_calibrate failed: STATUS - ADC not valid.\n"); >> + return -ENODATA; >> + } >> + lux_val = tsl2x7x_get_lux(indio_dev); >> + if (lux_val< 0) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_als_calibrate failed to get lux\n"); >> + return lux_val; >> + } >> + gain_trim_val = (((chip->tsl2x7x_settings.als_cal_target) >> + * chip->tsl2x7x_settings.als_gain_trim) / lux_val); >> + >> + if ((gain_trim_val< 250) || (gain_trim_val> 4000)) >> + return -ERANGE; >> + >> + chip->tsl2x7x_settings.als_gain_trim = gain_trim_val; >> + >> + dev_info(&chip->client->dev, >> + "%s als_calibrate completed\n", chip->client->name); >> + >> + return (int) gain_trim_val; >> +} >> + >> +/* >> + * Turn the device on. >> + * Configuration must be set before calling this function. >> + */ >> +static int tsl2x7x_chip_on(struct iio_dev *indio_dev) >> +{ >> + int i; >> + int ret = 0; >> + u8 *dev_reg; >> + u8 utmp; >> + int als_count; >> + int als_time; >> + struct tsl2X7X_chip *chip = iio_priv(indio_dev); >> + u8 reg_val = 0; >> + >> + if (chip->pdata&& chip->pdata->power_on) >> + chip->pdata->power_on(indio_dev); >> + >> + /* Non calculated parameters */ >> + chip->tsl2x7x_config[TSL2X7X_PRX_TIME] = >> + chip->tsl2x7x_settings.prx_time; >> + chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] = >> + chip->tsl2x7x_settings.wait_time; >> + chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] = >> + chip->tsl2x7x_settings.prox_config; >> + >> + chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] = >> + (chip->tsl2x7x_settings.als_thresh_low)& 0xFF; >> + chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] = >> + (chip->tsl2x7x_settings.als_thresh_low>> 8)& 0xFF; >> + chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] = >> + (chip->tsl2x7x_settings.als_thresh_high)& 0xFF; >> + chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] = >> + (chip->tsl2x7x_settings.als_thresh_high>> 8)& 0xFF; >> + chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] = >> + chip->tsl2x7x_settings.als_persistence; >> + >> + chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] = >> + chip->tsl2x7x_settings.prox_pulse_count; >> + chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] = >> + chip->tsl2x7x_settings.prox_thres_low; >> + chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] = >> + chip->tsl2x7x_settings.prox_thres_high; >> + >> + /* and make sure we're not already on */ >> + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { >> + /* if forcing a register update - turn off, then on */ >> + dev_info(&chip->client->dev, "device is already enabled\n"); >> + return -EINVAL; >> + } >> + >> + /* determine als integration regster */ >> + als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270; >> + if (als_count == 0) >> + als_count = 1; /* ensure at least one cycle */ >> + >> + /* convert back to time (encompasses overrides) */ >> + als_time = (als_count * 27 + 5) / 10; >> + chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count; >> + >> + /* Set the gain based on tsl2x7x_settings struct */ >> + chip->tsl2x7x_config[TSL2X7X_GAIN] = >> + (chip->tsl2x7x_settings.als_gain | (mA100 | DIODE1) >> + | ((chip->tsl2x7x_settings.prox_gain)<< 2)); >> + >> + /* set chip struct re scaling and saturation */ >> + chip->als_saturation = als_count * 922; /* 90% of full scale */ >> + chip->als_time_scale = (als_time + 25) / 50; >> + >> + /* TSL2X7X Specific power-on / adc enable sequence >> + * Power on the device 1st. */ >> + utmp = TSL2X7X_CNTL_PWR_ON; >> + ret = i2c_smbus_write_byte_data(chip->client, >> + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); >> + if (ret< 0) { >> + dev_err(&chip->client->dev, "tsl2x7x_chip_on failed on CNTRL >> reg.\n"); >> + return -1; >> + } >> + >> + /* Use the following shadow copy for our delay before enabling ADC. >> + * Write all the registers. */ >> + for (i = 0, dev_reg = chip->tsl2x7x_config; i< TSL2X7X_REG_MAX; >> i++) { >> + ret = i2c_smbus_write_byte_data(chip->client, >> + TSL2X7X_CMD_REG + i, *dev_reg++); >> + if (ret< 0) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_chip_on failed on write to reg %d.\n", i); >> + return ret; >> + } >> + } >> + >> + udelay(3000); /* Power-on settling time */ >> + >> + /* NOW enable the ADC >> + * initialize the desired mode of operation */ >> + utmp = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL | >> CNTL_PROX_DET_ENBL; >> + ret = i2c_smbus_write_byte_data(chip->client, >> + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp); >> + if (ret< 0) { >> + dev_err(&chip->client->dev, "tsl2x7x_chip_on failed on 2nd >> CTRL reg.\n"); >> + return ret; >> + } >> + >> + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING; >> + >> + if (chip->tsl2x7x_settings.interrupts_en != 0) { >> + dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n"); >> + /* first time interrupt */ >> + chip->init_done = 0; >> + >> + >> + reg_val = TSL2X7X_CNTL_PWR_ON; >> + >> + if (chip->tsl2x7x_settings.interrupts_en == 0x10) >> + reg_val |= CNTL_ADC_ENBL; >> + >> + if (chip->tsl2x7x_settings.interrupts_en == 0x20) >> + reg_val |= CNTL_PROX_DET_ENBL; >> + >> + if (chip->tsl2x7x_settings.interrupts_en == 0x30) >> + reg_val |= (CNTL_ADC_ENBL | CNTL_PROX_DET_ENBL); >> + >> + reg_val |= chip->tsl2x7x_settings.interrupts_en; >> + >> + ret = i2c_smbus_write_byte_data(chip->client, >> + (TSL2X7X_CMD_REG | TSL2X7X_CNTRL), reg_val); >> + if (ret< 0) >> + dev_err(&chip->client->dev, >> + "tsl2x7x_i2c_write to device failed in >> tsl2x7x_IOCTL_INT_SET.\n"); >> + >> + /* Clear out any initial interrupts */ >> + ret = i2c_smbus_write_byte(chip->client, >> + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | >> + TSL2X7X_CMD_PROXALS_INTCLR); >> + if (ret< 0) { >> + dev_err(&chip->client->dev, >> + "tsl2x7x_i2c_write_command failed in tsl2x7x_chip_on\n"); >> + return ret; >> + } >> + } >> + return ret; >> + >> +} >> + >> +static int tsl2x7x_chip_off(struct iio_dev *indio_dev) >> +{ >> + int ret; >> + struct tsl2X7X_chip *chip = iio_priv(indio_dev); >> + >> + /* turn device off */ >> + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; >> + >> + ret = i2c_smbus_write_byte_data(chip->client, >> + TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00); >> + >> + if (chip->pdata&& chip->pdata->power_off) >> + chip->pdata->power_off(chip->client); >> + >> + return ret; >> +} >> + >> +/** >> + * Integer Square Root >> + * We need an integer version since 1st Floating point is not allowed >> + * in driver world, 2nd, cannot count on the devices having a FPU, and >> + * 3rd software FP emulation may be excessive. > It's exactly this sort of thing that supports my argument below that > this ought to be > in userspace... >> + */ >> +static unsigned long tsl2x7x_isqrt(unsigned long x) >> +{ >> + register unsigned long op, res, one; >> + op = x; >> + res = 0; >> + >> + one = 1<< 30; >> + while (one> op) >> + one>>= 2; >> + >> + while (one != 0) { >> + if (op>= res + one) { >> + op -= res + one; >> + res += one<< 1; >> + } >> + res>>= 1; >> + one>>= 2; >> + } >> + return res; >> +} >> + >> +/* >> + * Proximity calibration helper function >> + * runs through a collection of data samples, >> + * sets the min, max, mean, and std dev. >> + */ >> +static >> +void tsl2x7x_prox_calculate(u16 *data, int length, struct prox_stat >> *statP) >> +{ >> + int i; >> + int min, max, sum, mean; >> + unsigned long stddev; >> + int tmp; >> + >> + if (length == 0) >> + length = 1; >> + >> + sum = 0; >> + min = 0xffff; >> + max = 0; >> + for (i = 0; i< length; i++) { >> + sum += data[i]; >> + if (data[i]< min) >> + min = data[i]; >> + if (data[i]> max) >> + max = data[i]; >> + } >> + mean = sum/length; >> + statP->min = min; >> + statP->max = max; >> + statP->mean = mean; >> + >> + sum = 0; >> + for (i = 0; i< length; i++) { >> + tmp = data[i]-mean; >> + sum += tmp * tmp; >> + } >> + stddev = tsl2x7x_isqrt((long)sum)/length; >> + statP->stddev = stddev; >> + >> +} >> + >> +/** >> + * Proximity calibration - collects a number of samples, >> + * calculates a standard deviation based on the samples, and >> + * sets the threshold accordingly. >> + */ > I guess you have a demand for this, but generally I'd feel this had more > of a place in userspace than down in the kernel... >> +static void tsl2x7x_prox_cal(struct iio_dev *indio_dev) >> +{ >> + u16 prox_history[MAX_SAMPLES_CAL+1]; >> + int i; >> + struct prox_stat prox_stat_data[2]; >> + struct prox_stat *calP; >> + struct tsl2X7X_chip *chip = iio_priv(indio_dev); >> + u8 tmp_irq_settings; >> + u8 current_state = chip->tsl2x7x_chip_status; >> + >> + if (chip->tsl2x7x_settings.prox_max_samples_cal> >> MAX_SAMPLES_CAL) { >> + dev_err(&chip->client->dev, >> + "max prox samples cal is too big: %d\n", >> + chip->tsl2x7x_settings.prox_max_samples_cal); >> + chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL; >> + } >> + >> + /* have to stop to change settings */ >> + tsl2x7x_chip_off(indio_dev); >> + >> + /* Enable proximity detection save just in case prox not wanted >> yet*/ >> + tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en; >> + chip->tsl2x7x_settings.interrupts_en |= CNTL_PROX_INT_ENBL; >> + >> + /*turn on device if not already on*/ >> + tsl2x7x_chip_on(indio_dev); >> + >> + /*gather the samples*/ >> + for (i = 0; i< chip->tsl2x7x_settings.prox_max_samples_cal; i++) { >> + mdelay(15); >> + tsl2x7x_prox_poll(indio_dev); >> + prox_history[i] = chip->prox_cur_info.prox_data; >> + dev_info(&chip->client->dev, "2 i=%d prox data= %d\n", >> + i, chip->prox_cur_info.prox_data); >> + >> + } >> + >> + tsl2x7x_chip_off(indio_dev); >> + >> + calP =&prox_stat_data[PROX_STAT_CAL]; >> + tsl2x7x_prox_calculate(prox_history, >> + chip->tsl2x7x_settings.prox_max_samples_cal, calP); >> + chip->tsl2x7x_settings.prox_thres_high = (calP->max<< 1) - >> calP->mean; >> + >> + dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n", >> + calP->min, calP->mean, calP->max); >> + dev_info(&chip->client->dev, >> + "%s proximity threshold set to %d\n", >> + chip->client->name, chip->tsl2x7x_settings.prox_thres_high); >> + >> + /* back to the way they were */ >> + chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings; >> + if (current_state == TSL2X7X_CHIP_WORKING) >> + tsl2x7x_chip_on(indio_dev); >> +} >> + >> +/* ---------- Sysfs Interface Functions ------------- */ > Don't bother with the structure comments. It's readily apparent and they > have a nasty habit of not being true after a year or two. >> + >> + >> +static ssize_t tsl2x7x_power_state_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status); >> +} >> + >> +static ssize_t tsl2x7x_power_state_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; > strtobool >> + >> + if (value == 0) >> + tsl2x7x_chip_off(dev_info); >> + else >> + tsl2x7x_chip_on(dev_info); >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_proximity_detect_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + tsl2x7x_prox_poll(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + chip->prox_cur_info.prox_event); >> +} >> + >> +static ssize_t tsl2x7x_gain_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain].ch0); >> +} >> + >> +static ssize_t tsl2x7x_gain_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + switch (value) { >> + case 1: >> + chip->tsl2x7x_settings.als_gain = 0; >> + break; >> + case 8: >> + chip->tsl2x7x_settings.als_gain = 1; >> + break; >> + case 16: >> + chip->tsl2x7x_settings.als_gain = 2; >> + break; >> + case 120: >> + chip->tsl2x7x_settings.als_gain = 3; >> + break; > It's unlikely but you probably want to verify that 120 is only used > for parts where it is valid. (for consistency sake). >> + case 128: >> + chip->tsl2x7x_settings.als_gain = 3; >> + break; >> + >> + default: >> + dev_err(dev, >> + "Invalid Gain Index\n"); >> + return -EINVAL; >> + } >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_gain_available_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + if (strncmp(chip->client->name, "tsl2772", 7) == 0) >> + return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128"); >> + else >> + return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120"); >> +} >> + >> +static ssize_t tsl2x7x_prox_gain_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + (1<< chip->tsl2x7x_settings.prox_gain)); >> +} >> + >> +static ssize_t tsl2x7x_prox_gain_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + switch (value) { >> + case 1: > maybe use the relevant log2? Then you just need to check if it's too big. >> + chip->tsl2x7x_settings.prox_gain = 0; >> + break; >> + case 2: >> + chip->tsl2x7x_settings.prox_gain = 1; >> + break; >> + case 4: >> + chip->tsl2x7x_settings.prox_gain = 2; >> + break; >> + case 8: >> + chip->tsl2x7x_settings.prox_gain = 3; >> + break; >> + default: >> + dev_err(dev, >> + "Invalid Prox Gain Index\n"); >> + return -EINVAL; >> + } >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8"); >> +} >> + >> +static ssize_t tsl2x7x_als_time_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + chip->tsl2x7x_settings.als_time); >> +} >> + >> +static ssize_t tsl2x7x_als_time_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + if ((value< 50) || (value> 650)) >> + return -EINVAL; >> + >> + if (value % 50) >> + return -EINVAL; >> + >> + chip->tsl2x7x_settings.als_time = value; >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_als_time_available_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + return snprintf(buf, PAGE_SIZE, "%s\n", >> + "50 100 150 200 250 300 350 400 450 500 550 600 650"); >> +} >> + >> +static ssize_t tsl2x7x_als_trim_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + chip->tsl2x7x_settings.als_gain_trim); >> +} >> + >> +static ssize_t tsl2x7x_als_trim_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + if (value) > I'd have thought 0 was a valid gain_trim? >> + chip->tsl2x7x_settings.als_gain_trim = value; >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_als_cal_target_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + chip->tsl2x7x_settings.als_cal_target); >> +} >> + >> +static ssize_t tsl2x7x_als_cal_target_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + if (value) >> + chip->tsl2x7x_settings.als_cal_target = value; >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_interrupts_en_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + if (chip->tsl2x7x_settings.interrupts_en& 0x10) >> + return snprintf(buf, PAGE_SIZE, "%d\n", 1); >> + else >> + return snprintf(buf, PAGE_SIZE, "%d\n", 0); > snprintf(buf, PAGE_SIZE, "%d\n", > !!(chip->tsl2x7x_settings.interrupts_en & 0x10)); >> +} >> + >> +static ssize_t tsl2x7x_interrupts_en_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + > strotobool (and use the iio_chan_spec and relevant callbacks please.) >> + if (value> 1) >> + return -EINVAL; >> + if (value) >> + chip->tsl2x7x_settings.interrupts_en |= 0x10; >> + else >> + chip->tsl2x7x_settings.interrupts_en&= 0x20; >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_prox_interrupt_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + if (chip->tsl2x7x_settings.interrupts_en& 0x20) >> + return snprintf(buf, PAGE_SIZE, "%d\n", 1); >> + else >> + return snprintf(buf, PAGE_SIZE, "%d\n", 0); >> +} >> + >> +static ssize_t tsl2x7x_prox_interrupt_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + if (value> 1) >> + return -EINVAL; >> + if (value) >> + chip->tsl2x7x_settings.interrupts_en |= 0x20; >> + else >> + chip->tsl2x7x_settings.interrupts_en&= 0x10; >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_als_thresh_low_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + chip->tsl2x7x_settings.als_thresh_low); >> +} >> + >> +static ssize_t tsl2x7x_als_thresh_low_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + chip->tsl2x7x_settings.als_thresh_low = value; >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_als_thresh_high_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + chip->tsl2x7x_settings.als_thresh_high); >> +} >> + >> +static ssize_t tsl2x7x_als_thresh_high_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + chip->tsl2x7x_settings.als_thresh_high = value; >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_prox_thresh_low_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + chip->tsl2x7x_settings.prox_thres_low); >> +} >> + >> +static ssize_t tsl2x7x_prox_thresh_low_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + chip->tsl2x7x_settings.prox_thres_low = value; >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_prox_thresh_high_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + chip->tsl2x7x_settings.prox_thres_high); >> +} >> + >> +static ssize_t tsl2x7x_prox_thresh_high_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + chip->tsl2x7x_settings.prox_thres_high = value; >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_prox_data_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + tsl2x7x_prox_poll(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", >> + chip->prox_cur_info.prox_data); >> +} >> + >> +/* sampling_frequency AKA persistence in data sheet */ >> +static ssize_t tsl2x7x_als_persistence_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "0x%02X\n", >> + chip->tsl2x7x_settings.als_persistence); >> +} >> + >> +static ssize_t tsl2x7x_als_persistence_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; >> + >> + chip->tsl2x7x_settings.als_persistence = value; >> + >> + return len; >> +} >> + >> +static >> +ssize_t tsl2x7x_als_persistence_available_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + return snprintf(buf, PAGE_SIZE, "0x00 - 0xFF (0 - 255)\n"); >> +} >> + >> +static >> +ssize_t tsl2x7x_lux_show(struct device *dev, struct device_attribute >> *attr, >> + char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + int lux; >> + >> + lux = tsl2x7x_get_lux(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "%d\n", lux); >> +} >> + >> +static >> +ssize_t tsl2x7x_adc_show(struct device *dev, struct device_attribute >> *attr, >> + char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + tsl2x7x_get_lux(dev_info); >> + >> + return snprintf(buf, PAGE_SIZE, "0x%08x\n", >> + ((chip->als_cur_info.als_ch0<< 16) | >> + chip->als_cur_info.als_ch1)); > Your outputing in hex? Please don't and please do this through an > iio_chan_spec > structure and read_raw callback. >> +} >> + >> +static ssize_t tsl2x7x_do_calibrate(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; > strtobool? >> + >> + if (value == 1) >> + tsl2x7x_als_calibrate(dev_info); >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_luxtable_show(struct device *dev, >> + struct device_attribute *attr, char *buf) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + int i; >> + int offset = 0; >> + >> + i = 0; >> + while (i< (MAX_TABLE_SIZE * 3)) { >> + offset += snprintf(buf + offset, PAGE_SIZE, "%d,%d,%d,", >> + chip->tsl2x7x_device_lux[i].ratio, >> + chip->tsl2x7x_device_lux[i].ch0, >> + chip->tsl2x7x_device_lux[i].ch1); >> + if (chip->tsl2x7x_device_lux[i].ratio == 0) { >> + /* We just printed the first "0" entry. >> + * Now get rid of the extra "," and break. */ >> + offset--; >> + break; >> + } >> + i++; >> + } >> + >> + offset += snprintf(buf + offset, PAGE_SIZE, "\n"); >> + return offset; >> +} >> + >> +static ssize_t tsl2x7x_luxtable_store(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + int value[ARRAY_SIZE(chip->tsl2x7x_device_lux)*3 + 1]; >> + int n; >> + >> + get_options(buf, ARRAY_SIZE(value), value); >> + >> + /* We now have an array of ints starting at value[1], and >> + * enumerated by value[0]. >> + * We expect each group of three ints is one table entry, >> + * and the last table entry is all 0. >> + */ >> + n = value[0]; >> + if ((n % 3) || n< 6 || >> + n> ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) { >> + dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n); >> + return -EINVAL; >> + } >> + >> + if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) { >> + dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n); >> + return -EINVAL; >> + } >> + >> + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) >> + tsl2x7x_chip_off(dev_info); >> + >> + /* Zero out the table */ >> + memset(chip->tsl2x7x_device_lux, 0, >> sizeof(chip->tsl2x7x_device_lux)); >> + memcpy(chip->tsl2x7x_device_lux,&value[1], (value[0] * 4)); >> + >> + return len; >> +} >> + >> +static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev, >> + struct device_attribute *attr, const char *buf, size_t len) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + unsigned long value; >> + >> + if (kstrtoul(buf, 0,&value)) >> + return -EINVAL; > strtobool probably? >> + >> + if (value == 1) >> + tsl2x7x_prox_cal(dev_info); >> + >> + return len; >> +} >> + >> +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, >> + tsl2x7x_power_state_show, tsl2x7x_power_state_store); >> + >> +static DEVICE_ATTR(proximity_raw, S_IRUGO, >> + tsl2x7x_proximity_detect_show, NULL); >> + >> +static DEVICE_ATTR(intensity_infrared_raw, S_IRUGO, >> + tsl2x7x_prox_data_show, NULL); >> + >> + >> +static DEVICE_ATTR(proximity_calibscale, S_IRUGO | S_IWUSR, >> + tsl2x7x_prox_gain_show, tsl2x7x_prox_gain_store); >> +static DEVICE_ATTR(proximity_calibscale_available, S_IRUGO, >> + tsl2x7x_prox_gain_available_show, NULL); >> + >> +static DEVICE_ATTR(illuminance0_calibscale, S_IRUGO | S_IWUSR, >> + tsl2x7x_gain_show, tsl2x7x_gain_store); >> +static DEVICE_ATTR(illuminance0_calibscale_available, S_IRUGO, >> + tsl2x7x_gain_available_show, NULL); >> + >> +static DEVICE_ATTR(illuminance0_integration_time, S_IRUGO | S_IWUSR, >> + tsl2x7x_als_time_show, tsl2x7x_als_time_store); >> +static DEVICE_ATTR(illuminance0_integration_time_available, S_IRUGO, >> + tsl2x7x_als_time_available_show, NULL); >> + >> +static DEVICE_ATTR(illuminance0_calibbias, S_IRUGO | S_IWUSR, >> + tsl2x7x_als_trim_show, tsl2x7x_als_trim_store); >> + >> +static DEVICE_ATTR(illuminance0_input_target, S_IRUGO | S_IWUSR, >> + tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store); >> + >> +static DEVICE_ATTR(illuminance0_both_raw, S_IRUGO, tsl2x7x_adc_show, >> + NULL); >> + >> +static DEVICE_ATTR(illuminance0_input, S_IRUGO, tsl2x7x_lux_show, >> + NULL); >> +static DEVICE_ATTR(illuminance0_calibrate, S_IWUSR, NULL, >> + tsl2x7x_do_calibrate); >> +static DEVICE_ATTR(proximity_calibrate, S_IWUSR, NULL, >> + tsl2x7x_do_prox_calibrate); >> + >> +static DEVICE_ATTR(illuminance0_lux_table, S_IRUGO | S_IWUSR, >> + tsl2x7x_luxtable_show, tsl2x7x_luxtable_store); >> + >> +static DEVICE_ATTR(illuminance0_thresh_falling_value, S_IRUGO | >> S_IWUSR, >> + tsl2x7x_als_thresh_low_show, tsl2x7x_als_thresh_low_store); >> + >> +static DEVICE_ATTR(illuminance0_thresh_rising_value, S_IRUGO | S_IWUSR, >> + tsl2x7x_als_thresh_high_show, tsl2x7x_als_thresh_high_store); >> + >> +static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR, >> + tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store); >> + >> +static DEVICE_ATTR(sampling_frequency_available, S_IRUGO, >> + tsl2x7x_als_persistence_available_show, NULL); >> + >> +static DEVICE_ATTR(proximity_thresh_rising_value, S_IRUGO | S_IWUSR, >> + tsl2x7x_prox_thresh_high_show, tsl2x7x_prox_thresh_high_store); >> + >> +static DEVICE_ATTR(proximity_thresh_falling_value, S_IRUGO | S_IWUSR, >> + tsl2x7x_prox_thresh_low_show, tsl2x7x_prox_thresh_low_store); >> + > A lot of what we having in here is standard and should be done via a > iio_chan_spec > definition. That'll cover calibscal, calibbias, input, raw, > thresh_rising_value, thresh_falling_value > (which incidentally should be in the event attributes). > That leaves us with > power_state - ideally not here but handled via a kernel wide control > (it gets suggested, > everyone agrees it's a good idea and no one implements it...) but such > is life. > calibscale_available - fine > integration_time - Propose adding this to the iio_chan_spec via > info_mask. > integration_time_available - fine. > input_target -> target_input but otherwise fine. > calibrate -> fine > lux_table -> fine > sampling_frequency, frequency_available fine. > > Just for reference, we really need to come up with a way of handing > 'available' within > the iio_chan_spec structures and the same for sampling frequency. Not > your problem > but if I say it often enough hopefully someone else will do it ;) >> +static struct attribute *tsl2571_device_attrs[] = { >> + &dev_attr_power_state.attr, >> + &dev_attr_illuminance0_calibscale.attr, >> + &dev_attr_illuminance0_calibscale_available.attr, >> + &dev_attr_illuminance0_integration_time.attr, >> + &dev_attr_illuminance0_integration_time_available.attr, >> + &dev_attr_illuminance0_calibbias.attr, >> + &dev_attr_illuminance0_input_target.attr, >> + &dev_attr_illuminance0_both_raw.attr, >> + &dev_attr_illuminance0_input.attr, >> + &dev_attr_illuminance0_calibrate.attr, >> + &dev_attr_illuminance0_lux_table.attr, >> + &dev_attr_illuminance0_thresh_falling_value.attr, >> + &dev_attr_illuminance0_thresh_rising_value.attr, >> + &dev_attr_sampling_frequency.attr, >> + &dev_attr_sampling_frequency_available.attr, >> + NULL >> +}; >> + >> +static struct attribute *tsl2671_device_attrs[] = { >> + &dev_attr_power_state.attr, >> + &dev_attr_proximity_raw.attr, >> + &dev_attr_intensity_infrared_raw.attr, >> + &dev_attr_sampling_frequency.attr, >> + &dev_attr_sampling_frequency_available.attr, >> + &dev_attr_proximity_thresh_rising_value.attr, >> + &dev_attr_proximity_thresh_falling_value.attr, >> + &dev_attr_proximity_calibrate.attr, >> + NULL >> +}; >> + >> +static struct attribute *tsl2771_device_attrs[] = { >> + &dev_attr_power_state.attr, >> + &dev_attr_proximity_raw.attr, >> + &dev_attr_intensity_infrared_raw.attr, >> + &dev_attr_illuminance0_calibscale.attr, >> + &dev_attr_illuminance0_calibscale_available.attr, >> + &dev_attr_illuminance0_integration_time.attr, >> + &dev_attr_illuminance0_integration_time_available.attr, >> + &dev_attr_illuminance0_calibbias.attr, >> + &dev_attr_illuminance0_input_target.attr, >> + &dev_attr_illuminance0_both_raw.attr, >> + &dev_attr_illuminance0_input.attr, >> + &dev_attr_illuminance0_calibrate.attr, >> + &dev_attr_illuminance0_lux_table.attr, >> + &dev_attr_illuminance0_thresh_falling_value.attr, >> + &dev_attr_illuminance0_thresh_rising_value.attr, >> + &dev_attr_sampling_frequency.attr, >> + &dev_attr_sampling_frequency_available.attr, >> + &dev_attr_proximity_thresh_rising_value.attr, >> + &dev_attr_proximity_thresh_falling_value.attr, >> + &dev_attr_proximity_calibrate.attr, >> + NULL >> +}; >> + >> +static struct attribute *tsl2572_device_attrs[] = { >> + &dev_attr_power_state.attr, >> + &dev_attr_illuminance0_calibscale.attr, >> + &dev_attr_illuminance0_calibscale_available.attr, >> + &dev_attr_illuminance0_integration_time.attr, >> + &dev_attr_illuminance0_integration_time_available.attr, >> + &dev_attr_illuminance0_calibbias.attr, >> + &dev_attr_illuminance0_input_target.attr, >> + &dev_attr_illuminance0_both_raw.attr, >> + &dev_attr_illuminance0_input.attr, >> + &dev_attr_illuminance0_calibrate.attr, >> + &dev_attr_illuminance0_lux_table.attr, >> + &dev_attr_illuminance0_thresh_falling_value.attr, >> + &dev_attr_illuminance0_thresh_rising_value.attr, >> + &dev_attr_sampling_frequency.attr, >> + &dev_attr_sampling_frequency_available.attr, >> + NULL >> +}; >> + >> +static struct attribute *tsl2672_device_attrs[] = { >> + &dev_attr_power_state.attr, >> + &dev_attr_proximity_raw.attr, >> + &dev_attr_intensity_infrared_raw.attr, >> + &dev_attr_proximity_calibscale.attr, >> + &dev_attr_sampling_frequency.attr, >> + &dev_attr_sampling_frequency_available.attr, >> + &dev_attr_proximity_thresh_rising_value.attr, >> + &dev_attr_proximity_thresh_falling_value.attr, >> + &dev_attr_proximity_calibrate.attr, >> + NULL >> +}; >> + > Indent the same for all of these. >> +static struct attribute *tsl2772_device_attrs[] = { >> + &dev_attr_power_state.attr, >> + &dev_attr_proximity_raw.attr, >> + &dev_attr_proximity_calibscale.attr, >> + &dev_attr_intensity_infrared_raw.attr, >> + &dev_attr_illuminance0_calibscale.attr, >> + &dev_attr_illuminance0_calibscale_available.attr, >> + &dev_attr_illuminance0_integration_time.attr, >> + &dev_attr_illuminance0_integration_time_available.attr, >> + &dev_attr_illuminance0_calibbias.attr, >> + &dev_attr_illuminance0_input_target.attr, >> + &dev_attr_illuminance0_both_raw.attr, >> + &dev_attr_illuminance0_input.attr, >> + &dev_attr_illuminance0_calibrate.attr, >> + &dev_attr_illuminance0_lux_table.attr, >> + &dev_attr_illuminance0_thresh_falling_value.attr, >> + &dev_attr_illuminance0_thresh_rising_value.attr, >> + &dev_attr_sampling_frequency.attr, >> + &dev_attr_sampling_frequency_available.attr, >> + &dev_attr_proximity_thresh_rising_value.attr, >> + &dev_attr_proximity_thresh_falling_value.attr, >> + &dev_attr_proximity_calibrate.attr, >> + &dev_attr_proximity_calibscale_available.attr, >> + NULL >> +}; >> + >> +static struct attribute_group tsl2X7X_dev_attr_group_tbl[] = { >> + [tsl2571] = { >> + .attrs = tsl2571_device_attrs, >> + }, >> + [tsl2671] = { >> + .attrs = tsl2671_device_attrs, >> + }, >> + [tmd2671] = { >> + .attrs = tsl2671_device_attrs, >> + }, >> + [tsl2771] = { >> + .attrs = tsl2771_device_attrs, >> + }, >> + [tmd2771] = { >> + .attrs = tsl2771_device_attrs, >> + }, >> + [tsl2572] = { >> + .attrs = tsl2572_device_attrs, >> + }, >> + [tsl2672] = { >> + .attrs = tsl2672_device_attrs, >> + }, >> + [tmd2672] = { >> + .attrs = tsl2672_device_attrs, >> + }, >> + [tsl2772] = { >> + .attrs = tsl2772_device_attrs, >> + }, >> + [tmd2772] = { >> + .attrs = tsl2772_device_attrs, >> + }, >> + >> +}; >> + >> +static IIO_DEVICE_ATTR(illuminance_thresh_both_en, >> + S_IRUGO | S_IWUSR, >> + tsl2x7x_interrupts_en_show, tsl2x7x_interrupts_en_store, 0); >> + >> +static IIO_DEVICE_ATTR(proximity_thresh_both_en, >> + S_IRUGO | S_IWUSR, >> + tsl2x7x_prox_interrupt_show, tsl2x7x_prox_interrupt_store, 0); >> + >> +static struct attribute *tsl2X7X_prox_event_attributes[] = { >> + &iio_dev_attr_proximity_thresh_both_en.dev_attr.attr, >> + NULL, >> +}; >> + >> +static struct attribute *tsl2X7X_als_event_attributes[] = { >> + &iio_dev_attr_illuminance_thresh_both_en.dev_attr.attr, >> + NULL, >> +}; >> + >> +static struct attribute *tsl2X7X_proxals_event_attributes[] = { >> + &iio_dev_attr_illuminance_thresh_both_en.dev_attr.attr, >> + &iio_dev_attr_proximity_thresh_both_en.dev_attr.attr, >> + NULL, >> +}; > The way we have handled this for some similar devices is to just have > the two enables done > via the iio_chan_spec and chain them both to read / write the same > value. (By which I mean > the rising enable and falling enable). It slightly clunkier as an > interface, but saves code and will > ultimately enable them to be accessed by consumer drivers within the > kernel (not that we've > even started looking at event pass >> + >> +static struct attribute_group tsl2X7X_event_attr_group_tbl[] = { >> + [tsl2571] = { >> + .attrs = tsl2X7X_als_event_attributes, >> + .name = "events", >> + }, >> + [tsl2671] = { >> + .attrs = tsl2X7X_prox_event_attributes, >> + .name = "events", >> + }, >> + [tmd2671] = { >> + .attrs = tsl2X7X_prox_event_attributes, >> + .name = "events", >> + }, >> + [tsl2771] = { >> + .attrs = tsl2X7X_proxals_event_attributes, >> + .name = "events", >> + }, >> + [tmd2771] = { >> + .attrs = tsl2X7X_proxals_event_attributes, >> + .name = "events", >> + }, >> + >> + [tsl2572] = { >> + .attrs = tsl2X7X_als_event_attributes, >> + .name = "events", >> + }, >> + [tsl2672] = { >> + .attrs = tsl2X7X_prox_event_attributes, >> + .name = "events", >> + }, >> + [tmd2672] = { >> + .attrs = tsl2X7X_prox_event_attributes, >> + .name = "events", >> + }, >> + [tsl2772] = { >> + .attrs = tsl2X7X_proxals_event_attributes, >> + .name = "events", >> + }, >> + [tmd2772] = { >> + .attrs = tsl2X7X_proxals_event_attributes, >> + .name = "events", >> + } >> +}; >> + > Being fussy, but only one blank line please. >> + >> +/* Use the default register values to identify the Taos device */ >> +static int tsl2x7x_device_id(unsigned char *bufp, int target) >> +{ >> + switch (target) { >> + case tsl2571: >> + case tsl2671: >> + case tsl2771: >> + return ((bufp[TSL2X7X_CHIPID]& 0xf0) == TRITON_ID); >> + break; >> + case tmd2671: >> + case tmd2771: >> + return ((bufp[TSL2X7X_CHIPID]& 0xf0) == HALIBUT_ID); >> + break; >> + case tsl2572: >> + case tsl2672: >> + case tmd2672: >> + case tsl2772: >> + case tmd2772: >> + return ((bufp[TSL2X7X_CHIPID]& 0xf0) == SWORDFISH_ID); >> + break; >> + } >> + >> + return -EINVAL; >> +} >> + >> +static const struct iio_info tsl2X7X_info[] = { >> + [tsl2571] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2571], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2571], >> + .driver_module = THIS_MODULE, >> + }, >> + [tsl2671] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2671], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2671], >> + .driver_module = THIS_MODULE, >> + }, >> + [tmd2671] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2671], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2671], >> + .driver_module = THIS_MODULE, >> + }, >> + [tsl2771] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2771], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2771], >> + .driver_module = THIS_MODULE, >> + }, >> + [tmd2771] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2771], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2771], >> + .driver_module = THIS_MODULE, >> + }, >> + [tsl2572] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2572], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2572], >> + .driver_module = THIS_MODULE, >> + }, >> + [tsl2672] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2672], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2672], >> + .driver_module = THIS_MODULE, >> + }, >> + [tmd2672] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2672], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2672], >> + .driver_module = THIS_MODULE, >> + }, >> + [tsl2772] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2772], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2772], >> + .driver_module = THIS_MODULE, >> + }, >> + [tmd2772] = { >> + .attrs =&tsl2X7X_dev_attr_group_tbl[tsl2772], >> + .event_attrs =&tsl2X7X_event_attr_group_tbl[tsl2772], >> + .driver_module = THIS_MODULE, > A lot of repeats in here, could you not have fewer entries? Just > reuse the enum values > in the i2c id table below. >> + }, >> + >> +}; >> + >> +/* >> + * Run-time interrupt handler - depending on whether the device is >> in ambient >> + * light sensing interrupt mode, this handler can queue up >> + * a thread, to handle valid interrupts. >> + */ >> +static irqreturn_t tsl2x7x_event_handler(int irq, void *private) >> +{ >> + struct iio_dev *indio_dev = private; >> + struct tsl2X7X_chip *chip = iio_priv(indio_dev); >> + s64 timestamp = iio_get_time_ns(); >> + int ret; >> + int value; >> + >> + value = i2c_smbus_read_byte_data(chip->client, >> + TSL2X7X_CMD_REG | TSL2X7X_STATUS); >> + >> + /* What type of interrupt do we need to process */ >> + if (value& TSL2X7X_STA_PRX_INTR) { >> + tsl2x7x_prox_poll(indio_dev); >> + iio_push_event(indio_dev, >> + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, >> + 0, >> + IIO_EV_TYPE_THRESH, >> + IIO_EV_DIR_EITHER), >> + timestamp); >> + } >> + >> + if (value& TSL2X7X_STA_ALS_INTR) { >> + tsl2x7x_get_lux(indio_dev); >> + iio_push_event(indio_dev, >> + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, >> + 0, >> + IIO_EV_TYPE_THRESH, >> + IIO_EV_DIR_EITHER), >> + timestamp); >> + } >> + /* Clear interrupt now that we have the status */ >> + ret = i2c_smbus_write_byte(chip->client, >> + TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN | >> + TSL2X7X_CMD_PROXALS_INTCLR); >> + if (ret< 0) >> + dev_err(&chip->client->dev, >> + "Failed to clear irq from event handler. err = %d\n", ret); >> + >> + return IRQ_HANDLED; >> +} >> + >> +/* >> + * Client probe function. >> + */ >> +static int __devinit tsl2x7x_probe(struct i2c_client *clientp, >> + const struct i2c_device_id *id) >> +{ >> + int i, ret; >> + unsigned char buf[TSL2X7X_MAX_DEVICE_REGS]; >> + struct iio_dev *indio_dev = >> + iio_allocate_device(sizeof(struct tsl2X7X_chip)); > Ugly to do non trivial allocation in the variable definitions. Have > struct iio_dev *indio_dev; > struct tsl2x7x_chip *chip; > > indio_dev = iio_allocate_device(sizeof(*chip)); > if (indio_dev == NULL) { > } > chip = iio_priv(indio_dev); > etc. >> + struct tsl2X7X_chip *chip = iio_priv(indio_dev); >> + >> + if (indio_dev == NULL) { >> + ret = -ENOMEM; >> + dev_err(&clientp->dev, "iio allocation failed\n"); >> + goto fail1; >> + } >> + >> + chip = iio_priv(indio_dev); >> + chip->client = clientp; >> + i2c_set_clientdata(clientp, indio_dev); >> + >> + mutex_init(&chip->als_mutex); >> + mutex_init(&chip->prox_mutex); >> + >> + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN; >> + >> + chip->pdata = clientp->dev.platform_data; >> + if (chip->pdata&& chip->pdata->init) >> + chip->pdata->init(clientp); >> + >> + for (i = 0; i< TSL2X7X_MAX_DEVICE_REGS; i++) { >> + ret = i2c_smbus_write_byte(clientp, >> + (TSL2X7X_CMD_REG | (TSL2X7X_CNTRL + i))); >> + if (ret< 0) { >> + dev_err(&clientp->dev, "i2c_smbus_write_bytes() to cmd " >> + "reg failed in tsl2x7x_probe(), err = %d\n", ret); >> + goto fail1; >> + } >> + ret = i2c_smbus_read_byte(clientp); >> + if (ret< 0) { >> + dev_err(&clientp->dev, "i2c_smbus_read_byte from " >> + "reg failed in tsl2x7x_probe(), err = %d\n", ret); >> + >> + goto fail1; >> + } >> + buf[i] = ret; >> + } >> + >> + if ((!tsl2x7x_device_id(buf, id->driver_data)) || >> + (tsl2x7x_device_id(buf, id->driver_data) == -EINVAL)) { >> + dev_info(&chip->client->dev, "i2c device found but does not >> match " >> + "expected id in tsl2x7x_probe()\n"); >> + goto fail1; >> + } >> + >> + chip->id = id->driver_data; >> + >> + ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | >> TSL2X7X_CNTRL)); >> + if (ret< 0) { >> + dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg " >> + "failed in tsl2x7x_probe(), err = %d\n", ret); >> + goto fail1; >> + } >> + >> + indio_dev->info =&tsl2X7X_info[id->driver_data]; >> + indio_dev->dev.parent =&clientp->dev; >> + indio_dev->modes = INDIO_DIRECT_MODE; >> + indio_dev->name = chip->client->name; >> + indio_dev->channels = tsl2X7X_channels; >> + indio_dev->num_channels = ARRAY_SIZE(tsl2X7X_channels); >> + >> + ret = iio_device_register(indio_dev); >> + if (ret) { >> + dev_err(&clientp->dev, "iio registration failed\n"); >> + goto fail2; > one would normally expect a later failure to result in more needing to > be undone, > but it appears to be the other way around here. >> + } >> + >> + if (clientp->irq) { >> + ret = request_threaded_irq(clientp->irq, >> + NULL, >> + &tsl2x7x_event_handler, >> + IRQF_TRIGGER_RISING | IRQF_ONESHOT, >> + "TSL2X7X_event", >> + indio_dev); >> + if (ret) >> + dev_err(&clientp->dev, "irq request failed"); > Unwinding after this error? Generally set the irq up and make the > iio_device_register > pretty much the last thing to happen rather than this way around. > Nothing can > touch the device before the iio_device_register so it avoids the > chance of race > conditions without having to be careful! >> + } >> + >> + /* Load up the defaults */ >> + tsl2x7x_defaults(chip); >> + >> + /* Make sure the chip is on */ >> + tsl2x7x_chip_on(indio_dev); >> + >> + dev_info(&clientp->dev, "%s Light sensor found.\n", id->name); >> + >> + return 0; >> + >> +fail1: >> + if (chip->pdata&& chip->pdata->teardown) >> + chip->pdata->teardown(clientp); >> + iio_free_device(indio_dev); >> + >> +fail2: >> + return ret; > loose the bonus blank line. >> + >> +} >> + >> + >> +static int tsl2x7x_suspend(struct device *dev) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); > standardize the naming please. indio_dev preferably but consistency > is most > important. >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + >> + int ret = 0; >> + >> + /* Blocks if work is active */ >> + cancel_work_sync(&chip->work_thresh); >> + >> + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) { >> + ret = tsl2x7x_chip_off(dev_info); >> + chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED; >> + } >> + >> + if (chip->pdata&& chip->pdata->platform_power) { >> + pm_message_t pmm = {PM_EVENT_SUSPEND}; >> + chip->pdata->platform_power(dev, pmm); >> + } >> + >> + return ret; >> +} >> + >> +static int tsl2x7x_resume(struct device *dev) >> +{ >> + struct iio_dev *dev_info = dev_get_drvdata(dev); >> + struct tsl2X7X_chip *chip = iio_priv(dev_info); >> + int ret = 0; >> + >> + if (chip->pdata&& chip->pdata->platform_power) { >> + pm_message_t pmm = {PM_EVENT_RESUME}; >> + chip->pdata->platform_power(dev, pmm); >> + } >> + >> + if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED) >> + ret = tsl2x7x_chip_on(dev_info); >> + >> + return ret; >> +} >> + >> +static int __devexit tsl2x7x_remove(struct i2c_client *client) >> +{ >> + struct iio_dev *indio_dev = i2c_get_clientdata(client); >> + struct tsl2X7X_chip *chip = i2c_get_clientdata(client); > Err, the two lines above seem a little implausible. >> + >> + tsl2x7x_chip_off(indio_dev); >> + >> + if (client->irq) >> + free_irq(client->irq, chip->client->name); >> + >> + flush_scheduled_work(); >> + >> + iio_device_unregister(chip->iio_dev); > or use the indio_dev pointer you already have. There is rarely a reason > to have a pointer to the iio_dev in the driver private bit. >> + kfree(chip); >> + >> + if (chip->pdata&& chip->pdata->teardown) >> + chip->pdata->teardown(client); >> + >> + return 0; >> +} >> + >> +static struct i2c_device_id tsl2x7x_idtable[] = { > I'm guessing there is a magic ordering here, but might be > nicer just to go with alphabetical order.. >> + { "tsl2571", tsl2571 }, >> + { "tsl2671", tsl2671 }, >> + { "tmd2671", tmd2671 }, >> + { "tsl2771", tsl2771 }, >> + { "tmd2771", tmd2771 }, >> + { "tsl2572", tsl2572 }, >> + { "tsl2672", tsl2672 }, >> + { "tmd2672", tmd2672 }, >> + { "tsl2772", tsl2772 }, >> + { "tmd2772", tmd2772 }, >> + {} >> +}; >> + >> +MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable); >> + >> +static const struct dev_pm_ops tsl2x7x_pm_ops = { >> + .suspend = tsl2x7x_suspend, >> + .resume = tsl2x7x_resume, >> +}; >> + >> +/* Driver definition */ >> +static struct i2c_driver tsl2x7x_driver = { >> + .driver = { >> + .name = "tsl2X7X", >> + .pm =&tsl2x7x_pm_ops, >> + >> + }, >> + .id_table = tsl2x7x_idtable, >> + .probe = tsl2x7x_probe, >> + .remove = __devexit_p(tsl2x7x_remove), >> +}; >> + >> +static int __init tsl2x7x_init(void) >> +{ >> + return i2c_add_driver(&tsl2x7x_driver); >> +} >> + >> +static void __exit tsl2x7x_exit(void) >> +{ >> + i2c_del_driver(&tsl2x7x_driver); >> +} >> + >> +module_init(tsl2x7x_init); >> +module_exit(tsl2x7x_exit); > Some nice new macros to handle this boiler plate. > see module_i2c_driver in include/linux/i2c.h > >> + >> +MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>"); >> +MODULE_DESCRIPTION("TAOS tsl2X7X ambient light sensor driver"); >> +MODULE_LICENSE("GPL"); >> diff --git a/drivers/staging/iio/light/tsl2x7x_core.h >> b/drivers/staging/iio/light/tsl2x7x_core.h >> new file mode 100644 >> index 0000000..9a64412 >> --- /dev/null >> +++ b/drivers/staging/iio/light/tsl2x7x_core.h >> @@ -0,0 +1,138 @@ >> +/* >> + * Device driver for monitoring ambient light intensity (lux) >> + * and proximity (prox) within the TAOS TSL2X7X family of devices. >> + * >> + * Copyright (c) 2012, TAOS Corporation. >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License as published by >> + * the Free Software Foundation; either version 2 of the License, or >> + * (at your option) any later version. >> + * >> + * This program is distributed in the hope that it will be useful, >> but WITHOUT >> + * ANY WARRANTY; without even the implied warranty of >> MERCHANTABILITY or >> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public >> License for >> + * more details. >> + * >> + * You should have received a copy of the GNU General Public License >> along >> + * with this program; if not, write to the Free Software Foundation, >> Inc., >> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. >> + */ >> + >> +#ifndef __TSL2X7X_H >> +#define __TSL2X7X_H >> +#include<linux/pm.h> >> + >> +#include "../iio.h" > loose this header and just forward declare the pointer. > e.g. struct iio_dev; > >> + >> +/* TAOS Register definitions - note: >> + * depending on device, some of these register are not used and the >> + * register address is benign. >> + */ >> +/* 2X7X register offsets */ >> +#define TSL2X7X_MAX_DEVICE_REGS 32 >> +#define TSL2X7X_REG_MAX 16 >> + >> +/* Device Registers and Masks */ >> +#define TSL2X7X_CNTRL 0x00 >> +#define TSL2X7X_ALS_TIME 0X01 >> +#define TSL2X7X_PRX_TIME 0x02 >> +#define TSL2X7X_WAIT_TIME 0x03 >> +#define TSL2X7X_ALS_MINTHRESHLO 0X04 >> +#define TSL2X7X_ALS_MINTHRESHHI 0X05 >> +#define TSL2X7X_ALS_MAXTHRESHLO 0X06 >> +#define TSL2X7X_ALS_MAXTHRESHHI 0X07 >> +#define TSL2X7X_PRX_MINTHRESHLO 0X08 >> +#define TSL2X7X_PRX_MINTHRESHHI 0X09 >> +#define TSL2X7X_PRX_MAXTHRESHLO 0X0A >> +#define TSL2X7X_PRX_MAXTHRESHHI 0X0B >> +#define TSL2X7X_PERSISTENCE 0x0C >> +#define TSL2X7X_PRX_CONFIG 0x0D >> +#define TSL2X7X_PRX_COUNT 0x0E >> +#define TSL2X7X_GAIN 0x0F >> +#define TSL2X7X_NOTUSED 0x10 >> +#define TSL2X7X_REVID 0x11 >> +#define TSL2X7X_CHIPID 0x12 >> +#define TSL2X7X_STATUS 0x13 >> +#define TSL2X7X_ALS_CHAN0LO 0x14 >> +#define TSL2X7X_ALS_CHAN0HI 0x15 >> +#define TSL2X7X_ALS_CHAN1LO 0x16 >> +#define TSL2X7X_ALS_CHAN1HI 0x17 >> +#define TSL2X7X_PRX_LO 0x18 >> +#define TSL2X7X_PRX_HI 0x19 >> + >> +/* tsl2X7X cmd reg masks */ >> +#define TSL2X7X_CMD_REG 0x80 >> +#define TSL2X7X_CMD_SPL_FN 0x60 >> + >> +#define TSL2X7X_CMD_PROX_INT_CLR 0X05 >> +#define TSL2X7X_CMD_ALS_INT_CLR 0x06 >> +#define CMD_PROXALS_INT_CLR 0X07 >> + >> +/* tsl2X7X cntrl reg masks */ >> +#define TSL2X7X_CNTL_ADC_ENBL 0x02 >> +#define TSL2X7X_CNTL_PWR_ON 0x01 >> + >> +/* tsl2X7X status reg masks */ >> +#define TSL2X7X_STA_ADC_VALID 0x01 >> +#define TSL2X7X_STA_PRX_VALID 0x02 >> +#define TSL2X7X_STA_ADC_PRX_VALID 0x03 >> +#define TSL2X7X_STA_ALS_INTR 0x10 >> +#define TSL2X7X_STA_ADC_INTR 0x10 >> +#define TSL2X7X_STA_PRX_INTR 0x20 >> + >> +#define TSL2X7X_STA_ADC_INTR 0x10 >> + >> +/* tsl2X7X cntrl reg masks */ >> +#define CNTL_REG_CLEAR 0x00 >> +#define CNTL_PROX_INT_ENBL 0X20 >> +#define CNTL_ALS_INT_ENBL 0X10 >> +#define TSL2X7X_CNTL_WAIT_TMR_ENBL 0X08 >> +#define CNTL_PROX_DET_ENBL 0X04 >> +#define CNTL_ADC_ENBL 0x02 >> +#define TSL2X7X_CNTL_PWRON 0x01 >> +#define CNTL_ALSPON_ENBL 0x03 >> +#define CNTL_INTALSPON_ENBL 0x13 >> +#define CNTL_PROXPON_ENBL 0x0F >> +#define CNTL_INTPROXPON_ENBL 0x2F >> +#define TSL2X7X_CMD_PROXALS_INTCLR 0X07 >> + > Chances of a clash on these definitions is extremely high, > Stick a prefix in front of them to avoid that issue. >> +/*Prox diode to use */ >> +#define DIODE0 0x10 >> +#define DIODE1 0x20 >> +#define DIODE_BOTH 0x30 >> + >> +/* LED Power */ >> +#define mA100 0x00 >> +#define mA50 0x40 >> +#define mA25 0x80 >> +#define mA13 0xD0 >> + >> +/* Max number of segments allowable in LUX table */ >> +#define MAX_TABLE_SIZE 9 >> +#define MAX_DEFAULT_TABLE_BYTES (sizeof(int) * MAX_TABLE_SIZE) >> + >> +struct tsl2x7x_lux { >> + unsigned int ratio; >> + unsigned int ch0; >> + unsigned int ch1; >> +}; >> + >> + > Kernel doc for comments would be preferable. Can you also give a > description of what > actually tends to occur in these callbacks? I can't help feeling > there are rather more of > them than we'd normally expect. >> +/* struct tsl2x7x_platform_data - Assume all varients will have this */ >> +struct tsl2X7X_platform_data { >> + int (*platform_power)(struct device *dev, pm_message_t); >> + /* The following callback gets called when the TSL2772 is >> powered on */ >> + int (*power_on) (struct iio_dev *indio_dev); >> + /* The following callback gets called when the TSL2772 is >> powered off */ >> + int (*power_off) (struct i2c_client *dev); >> + /* The following callback gets called when the driver is added */ >> + int (*init) (struct i2c_client *dev); >> + /* The following callback gets called when the driver is removed */ >> + int (*teardown) (struct i2c_client *dev); >> + /* These are the device specific glass coefficents used to >> + * calculate Lux */ >> + struct tsl2x7x_lux platform_lux_table[MAX_TABLE_SIZE]; >> +}; >> + >> +#endif /* __TSL2X7X_H */ >> -- >> > > -- > To unsubscribe from this list: send the line "unsubscribe linux-iio" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-02-13 15:29 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-02-10 19:06 [PATCH V1] TAOS tsl2x7x Jon Brenner 2012-02-13 15:19 ` Jonathan Cameron 2012-02-13 15:28 ` Jonathan Cameron
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).