From: Vlad Zakharov <Vladislav.Zakharov@synopsys.com>
To: Michael Turquette <mturquette@baylibre.com>,
Stephen Boyd <sboyd@codeaurora.org>
Cc: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"mturquette@baylibre.com" <mturquette@baylibre.com>,
Jose Abreu <Jose.Abreu@synopsys.com>,
"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
"linux-snps-arc@lists.infradead.org"
<linux-snps-arc@lists.infradead.org>,
"mark.rutland@arm.com" <mark.rutland@arm.com>,
"robh@kernel.org" <robh@kernel.org>,
"linux-clk@vger.kernel.org" <linux-clk@vger.kernel.org>,
"sboyd@codeaurora.org" <sboyd@codeaurora.org>
Subject: Re: [PATCH v2] clk/axs10x: introduce AXS10X pll driver
Date: Fri, 3 Mar 2017 13:18:34 +0000 [thread overview]
Message-ID: <1488547113.2557.44.camel@synopsys.com> (raw)
In-Reply-To: <1487682670-4164-1-git-send-email-vzakhar@synopsys.com>
SGkgTWljaGFlbCwgU3RlcGhlbiwNCg0KT24gVHVlLCAyMDE3LTAyLTIxIGF0IDE2OjExICswMzAw
LCBWbGFkIFpha2hhcm92IHdyb3RlOg0KPiBBWFMxMFggYm9hcmRzIG1hbmFnZXMgaXQncyBjbG9j
a3MgdXNpbmcgdmFyaW91cyBQTExzLiBUaGVzZSBQTEwgaGFzIHNhbWUNCj4gZGl2aWRlcnMgYW5k
IGNvcnJlc3BvbmRpbmcgY29udHJvbCByZWdpc3RlcnMgbWFwcGVkIHRvIGRpZmZlcmVudCBhZGRy
ZXNzZXMuDQo+IFNvIHdlIGFkZCBvbmUgY29tbW9uIGRyaXZlciBmb3Igc3VjaCBQTExzLg0KPiAN
Cj4gRWFjaCBQTEwgb24gQVhTMTBYIGJvYXJkIGNvbnNpc3Qgb2YgdGhyZWUgZGl2aWRlcnM6IElE
SVYsIEZCRElWIGFuZA0KPiBPRElWLiBPdXRwdXQgY2xvY2sgdmFsdWUgaXMgbWFuYWdlZCB1c2lu
ZyB0aGVzZSBkaXZpZGVycy4NCj4gDQo+IFdlIGFkZCBwcmUtZGVmaW5lZCB0YWJsZXMgd2l0aCBz
dXBwb3J0ZWQgcmF0ZSB2YWx1ZXMgYW5kIGFwcHJvcHJpYXRlDQo+IGNvbmZpZ3VyYXRpb25zIG9m
IElESVYsIEZCRElWIGFuZCBPRElWIGZvciBlYWNoIHZhbHVlLg0KPiANCj4gQXMgb2YgdG9kYXkg
d2UgYWRkIHN1cHBvcnQgZm9yIFBMTHMgdGhhdCBnZW5lcmF0ZSBjbG9jayBmb3IgdGhlDQo+IGZv
bGxvd2luZyBkZXZpY2VzOg0KPiDCoCogQVJDIGNvcmUgb24gQVhDIENQVSB0aWxlcy4NCj4gwqAq
IEFSQyBQR1Ugb24gQVJDIFNEUCBNYWluYm9hcmQuDQo+IGFuZCBtb3JlIHRvIGNvbWUgbGF0ZXIu
DQo+IA0KPiBBY2tlZC1ieTogUm9iIEhlcnJpbmcgPHJvYmhAa2VybmVsLm9yZz4NCj4gU2lnbmVk
LW9mZi1ieTogVmxhZCBaYWtoYXJvdiA8dnpha2hhckBzeW5vcHN5cy5jb20+DQo+IFNpZ25lZC1v
ZmYtYnk6IEpvc2UgQWJyZXUgPGpvYWJyZXVAc3lub3BzeXMuY29tPg0KPiBDYzogTWljaGFlbCBU
dXJxdWV0dGUgPG10dXJxdWV0dGVAYmF5bGlicmUuY29tPg0KPiBDYzogU3RlcGhlbiBCb3lkIDxz
Ym95ZEBjb2RlYXVyb3JhLm9yZz4NCj4gQ2M6IE1hcmsgUnV0bGFuZCA8bWFyay5ydXRsYW5kQGFy
bS5jb20+DQo+IC0tLQ0KPiBDYzogUm9iIEhlcnJpbmcgPHJvYmhAa2VybmVsLm9yZz4NCj4gQ2hh
bmdlcyB2MS4udjINCj4gwqAtIFJlcGxhY2UgJ18nIHdpdGggJy0nIGluIGRldmljZSB0cmVlIG5v
ZGVzDQo+IA0KPiDCoC4uLi9kZXZpY2V0cmVlL2JpbmRpbmdzL2Nsb2NrL3NucHMscGxsLWNsb2Nr
LnR4dMKgwqDCoHzCoMKgMjggKysNCj4gwqBNQUlOVEFJTkVSU8KgwqDCoMKgwqDCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgfMKgwqDCoDYgKw0KPiDCoGRyaXZlcnMvY2xrL2F4czEweC9NYWtlZmlsZcKgwqDCoMKgwqDC
oMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoHzCoMKgwqAxICsNCj4gwqBkcml2
ZXJzL2Nsay9heHMxMHgvcGxsX2Nsb2NrLmPCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDC
oMKgwqDCoMKgwqB8IDM4NCArKysrKysrKysrKysrKysrKysrKysNCj4gwqA0IGZpbGVzIGNoYW5n
ZWQsIDQxOSBpbnNlcnRpb25zKCspDQo+IMKgY3JlYXRlIG1vZGUgMTAwNjQ0IERvY3VtZW50YXRp
b24vZGV2aWNldHJlZS9iaW5kaW5ncy9jbG9jay9zbnBzLHBsbC1jbG9jay50eHQNCj4gwqBjcmVh
dGUgbW9kZSAxMDA2NDQgZHJpdmVycy9jbGsvYXhzMTB4L3BsbF9jbG9jay5jDQo+IA0KPiBkaWZm
IC0tZ2l0IGEvRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL2Nsb2NrL3NucHMscGxs
LWNsb2NrLnR4dA0KPiBiL0RvY3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9jbG9jay9z
bnBzLHBsbC1jbG9jay50eHQNCj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gaW5kZXggMDAwMDAw
MC4uNTcwNjI0Ng0KPiAtLS0gL2Rldi9udWxsDQo+ICsrKyBiL0RvY3VtZW50YXRpb24vZGV2aWNl
dHJlZS9iaW5kaW5ncy9jbG9jay9zbnBzLHBsbC1jbG9jay50eHQNCj4gQEAgLTAsMCArMSwyOCBA
QA0KPiArQmluZGluZyBmb3IgdGhlIEFYUzEwWCBHZW5lcmljIFBMTCBjbG9jaw0KPiArDQo+ICtU
aGlzIGJpbmRpbmcgdXNlcyB0aGUgY29tbW9uIGNsb2NrIGJpbmRpbmdbMV0uDQo+ICsNCj4gK1sx
XSBEb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvY2xvY2svY2xvY2stYmluZGluZ3Mu
dHh0DQo+ICsNCj4gK1JlcXVpcmVkIHByb3BlcnRpZXM6DQo+ICstIGNvbXBhdGlibGU6IHNob3Vs
ZCBiZSAic25wcyxheHMxMHgtPG5hbWU+LXBsbC1jbG9jayINCj4gK8KgwqAic25wcyxheHMxMHgt
YXJjLXBsbC1jbG9jayINCj4gK8KgwqAic25wcyxheHMxMHgtcGd1LXBsbC1jbG9jayINCj4gKy0g
cmVnOiBzaG91bGQgYWx3YXlzIGNvbnRhaW4gMiBwYWlycyBhZGRyZXNzIC0gbGVuZ3RoOiBmaXJz
dCBmb3IgUExMIGNvbmZpZw0KPiArcmVnaXN0ZXJzIGFuZCBzZWNvbmQgZm9yIGNvcnJlc3BvbmRp
bmcgTE9DSyBDR1UgcmVnaXN0ZXIuDQo+ICstIGNsb2Nrczogc2hhbGwgYmUgdGhlIGlucHV0IHBh
cmVudCBjbG9jayBwaGFuZGxlIGZvciB0aGUgUExMLg0KPiArLSAjY2xvY2stY2VsbHM6IGZyb20g
Y29tbW9uIGNsb2NrIGJpbmRpbmc7IFNob3VsZCBhbHdheXMgYmUgc2V0IHRvIDAuDQo+ICsNCj4g
K0V4YW1wbGU6DQo+ICsJaW5wdXQtY2xrOiBpbnB1dC1jbGsgew0KPiArCQljbG9jay1mcmVxdWVu
Y3kgPSA8MzMzMzMzMzM+Ow0KPiArCQljb21wYXRpYmxlID0gImZpeGVkLWNsb2NrIjsNCj4gKwkJ
I2Nsb2NrLWNlbGxzID0gPDA+Ow0KPiArCX07DQo+ICsNCj4gKwljb3JlLWNsazogY29yZS1jbGtA
ODAgew0KPiArCQljb21wYXRpYmxlID0gInNucHMsYXhzMTB4LWFyYy1wbGwtY2xvY2siOw0KPiAr
CQlyZWcgPSA8MHg4MCAweDEwIDB4MTAwIDB4MTA+Ow0KPiArCQkjY2xvY2stY2VsbHMgPSA8MD47
DQo+ICsJCWNsb2NrcyA9IDwmaW5wdXQtY2xrPjsNCj4gKwl9Ow0KPiBkaWZmIC0tZ2l0IGEvTUFJ
TlRBSU5FUlMgYi9NQUlOVEFJTkVSUw0KPiBpbmRleCAzOTYwZTdmLi41ODA1ODMzIDEwMDY0NA0K
PiAtLS0gYS9NQUlOVEFJTkVSUw0KPiArKysgYi9NQUlOVEFJTkVSUw0KPiBAQCAtMTE5MTAsNiAr
MTE5MTAsMTIgQEAgRjoJYXJjaC9hcmMvcGxhdC1heHMxMHgNCj4gwqBGOglhcmNoL2FyYy9ib290
L2R0cy9heCoNCj4gwqBGOglEb2N1bWVudGF0aW9uL2RldmljZXRyZWUvYmluZGluZ3MvYXJjL2F4
czEwKg0KPiDCoA0KPiArU1lOT1BTWVMgQVJDIFNEUCBjbG9jayBkcml2ZXINCj4gK006CVZsYWQg
WmFraGFyb3YgPHZ6YWtoYXJAc3lub3BzeXMuY29tPg0KPiArUzoJU3VwcG9ydGVkDQo+ICtGOglk
cml2ZXJzL2Nsay9heHMxMHgvKg0KPiArRjoJRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRp
bmdzL2Nsb2NrL3NucHMscGxsLWNsb2NrLnR4dA0KPiArDQo+IMKgU1lTVEVNIENPTkZJR1VSQVRJ
T04gKFNZU0NPTikNCj4gwqBNOglMZWUgSm9uZXMgPGxlZS5qb25lc0BsaW5hcm8ub3JnPg0KPiDC
oE06CUFybmQgQmVyZ21hbm4gPGFybmRAYXJuZGIuZGU+DQo+IGRpZmYgLS1naXQgYS9kcml2ZXJz
L2Nsay9heHMxMHgvTWFrZWZpbGUgYi9kcml2ZXJzL2Nsay9heHMxMHgvTWFrZWZpbGUNCj4gaW5k
ZXggMDE5OTZiOC4uZDc0N2RlYSAxMDA2NDQNCj4gLS0tIGEvZHJpdmVycy9jbGsvYXhzMTB4L01h
a2VmaWxlDQo+ICsrKyBiL2RyaXZlcnMvY2xrL2F4czEweC9NYWtlZmlsZQ0KPiBAQCAtMSArMSwy
IEBADQo+IMKgb2JqLXkgKz0gaTJzX3BsbF9jbG9jay5vDQo+ICtvYmoteSArPSBwbGxfY2xvY2su
bw0KPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9jbGsvYXhzMTB4L3BsbF9jbG9jay5jIGIvZHJpdmVy
cy9jbGsvYXhzMTB4L3BsbF9jbG9jay5jDQo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0DQo+IGluZGV4
IDAwMDAwMDAuLjc4NGEwYTINCj4gLS0tIC9kZXYvbnVsbA0KPiArKysgYi9kcml2ZXJzL2Nsay9h
eHMxMHgvcGxsX2Nsb2NrLmMNCj4gQEAgLTAsMCArMSwzODQgQEANCj4gKy8qDQo+ICsgKiBTeW5v
cHN5cyBBWFMxMFggU0RQIEdlbmVyaWMgUExMIGNsb2NrIGRyaXZlcg0KPiArICoNCj4gKyAqIENv
cHlyaWdodCAoQykgMjAxNyBTeW5vcHN5cw0KPiArICoNCj4gKyAqIFRoaXMgZmlsZSBpcyBsaWNl
bnNlZCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYw0KPiArICogTGlj
ZW5zZSB2ZXJzaW9uIDIuIFRoaXMgcHJvZ3JhbSBpcyBsaWNlbnNlZCAiYXMgaXMiIHdpdGhvdXQg
YW55DQo+ICsgKiB3YXJyYW50eSBvZiBhbnkga2luZCwgd2hldGhlciBleHByZXNzIG9yIGltcGxp
ZWQuDQo+ICsgKi8NCj4gKw0KPiArI2luY2x1ZGUgPGxpbnV4L3BsYXRmb3JtX2RldmljZS5oPg0K
PiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2Nsay1wcm92
aWRlci5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L2RlbGF5Lmg+DQo+ICsjaW5jbHVkZSA8bGludXgv
ZXJyLmg+DQo+ICsjaW5jbHVkZSA8bGludXgvZGV2aWNlLmg+DQo+ICsjaW5jbHVkZSA8bGludXgv
b2ZfYWRkcmVzcy5oPg0KPiArI2luY2x1ZGUgPGxpbnV4L29mX2RldmljZS5oPg0KPiArI2luY2x1
ZGUgPGxpbnV4L3NsYWIuaD4NCj4gKyNpbmNsdWRlIDxsaW51eC9vZi5oPg0KPiArDQo+ICsvKiBQ
TEwgcmVnaXN0ZXJzIGFkZHJlc3NlcyAqLw0KPiArI2RlZmluZSBQTExfUkVHX0lESVYJMHgwDQo+
ICsjZGVmaW5lIFBMTF9SRUdfRkJESVYJMHg0DQo+ICsjZGVmaW5lIFBMTF9SRUdfT0RJVgkweDgN
Cj4gKw0KPiArLyoNCj4gKyAqIEJpdCBmaWVsZHMgb2YgdGhlIFBMTCBJRElWL0ZCRElWL09ESVYg
cmVnaXN0ZXJzOg0KPiArICrCoMKgX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQo+ICsgKiB8MzHCoMKgwqDCoMKg
wqDCoMKgwqDCoMKgwqDCoMKgwqDCoDE1fMKgwqDCoMKgMTTCoMKgwqDCoHzCoMKgwqAxM8KgwqDC
oHzCoMKgMTLCoMKgfDExwqDCoMKgwqDCoMKgwqDCoMKgNnw1wqDCoMKgwqDCoMKgwqDCoMKgMHwN
Cj4gKyAqIHwtLS0tLS0tUkVTUlZFRC0tLS0tLXwtTk9VUERBVEUtfC1CWVBBU1MtfC1FREdFLXwt
LUhJR0hUSU1FLS18LS1MT1dUSU1FLS18DQo+ICsgKiB8X19fX19fX19fX19fX19fX19fX198X19f
X19fX19fX3xfX19fX19fX3xfX19fX198X19fX19fX19fX19ffF9fX19fX19fX19ffA0KPiArICoN
Cj4gKyAqIEZvbGxvd2luZyBtYWNyb3MgZGV0aXJtaW5lIHRoZSB3YXkgb2YgYWNjZXNzIHRvIHRo
ZXNlIHJlZ2lzdGVycw0KPiArICogVGhleSBzaG91bGQgYmUgc2V0IHVwIG9ubHkgdXNpbmcgdGhl
IG1hY3Jvcy4NCj4gKyAqIHJlZyBzaG91bGQgYmUgYW5kIHVpbnQzMl90IHZhcmlhYmxlLg0KPiAr
ICovDQo+ICsNCj4gKyNkZWZpbmUgUExMX1JFR19HRVRfTE9XKHJlZykJCQlcDQo+ICsJKCgocmVn
KSAmICgweDNGIDw8IDApKSA+PiAwKQ0KPiArI2RlZmluZSBQTExfUkVHX0dFVF9ISUdIKHJlZykJ
CQlcDQo+ICsJKCgocmVnKSAmICgweDNGIDw8IDYpKSA+PiA2KQ0KPiArI2RlZmluZSBQTExfUkVH
X0dFVF9FREdFKHJlZykJCQlcDQo+ICsJKCgocmVnKSAmIChCSVQoMTIpKSkgPyAxIDogMCkNCj4g
KyNkZWZpbmUgUExMX1JFR19HRVRfQllQQVNTKHJlZykJCQlcDQo+ICsJKCgocmVnKSAmIChCSVQo
MTMpKSkgPyAxIDogMCkNCj4gKyNkZWZpbmUgUExMX1JFR19HRVRfTk9VUEQocmVnKQkJCVwNCj4g
KwkoKChyZWcpICYgKEJJVCgxNCkpKSA/IDEgOiAwKQ0KPiArI2RlZmluZSBQTExfUkVHX0dFVF9Q
QUQocmVnKQkJCVwNCj4gKwkoKChyZWcpICYgKDB4MUZGRkYgPDwgMTUpKSA+PiAxNSkNCj4gKw0K
PiArI2RlZmluZSBQTExfUkVHX1NFVF9MT1cocmVnLCB2YWx1ZSkJCVwNCj4gKwl7IHJlZyB8PSAo
KCh2YWx1ZSkgJiAweDNGKSA8PCAwKTsgfQ0KPiArI2RlZmluZSBQTExfUkVHX1NFVF9ISUdIKHJl
ZywgdmFsdWUpCVwNCj4gKwl7IHJlZyB8PSAoKCh2YWx1ZSkgJiAweDNGKSA8PCA2KTsgfQ0KPiAr
I2RlZmluZSBQTExfUkVHX1NFVF9FREdFKHJlZywgdmFsdWUpCVwNCj4gKwl7IHJlZyB8PSAoKCh2
YWx1ZSkgJiAweDAxKSA8PCAxMik7IH0NCj4gKyNkZWZpbmUgUExMX1JFR19TRVRfQllQQVNTKHJl
ZywgdmFsdWUpCVwNCj4gKwl7IHJlZyB8PSAoKCh2YWx1ZSkgJiAweDAxKSA8PCAxMyk7IH0NCj4g
KyNkZWZpbmUgUExMX1JFR19TRVRfTk9VUEQocmVnLCB2YWx1ZSkJXA0KPiArCXsgcmVnIHw9ICgo
KHZhbHVlKSAmIDB4MDEpIDw8IDE0KTsgfQ0KPiArI2RlZmluZSBQTExfUkVHX1NFVF9QQUQocmVn
LCB2YWx1ZSkJCVwNCj4gKwl7IHJlZyB8PSAoKCh2YWx1ZSkgJiAweDFGRkZGKSA8PCAxNSk7IH0N
Cj4gKw0KPiArI2RlZmluZSBQTExfTE9DSwkweDENCj4gKyNkZWZpbmUgUExMX01BWF9MT0NLX1RJ
TUUgMTAwIC8qIDEwMCB1cyAqLw0KPiArDQo+ICtzdHJ1Y3QgcGxsX2NmZyB7DQo+ICsJdTMyIHJh
dGU7DQo+ICsJdTMyIGlkaXY7DQo+ICsJdTMyIGZiZGl2Ow0KPiArCXUzMiBvZGl2Ow0KPiArfTsN
Cj4gKw0KPiArc3RydWN0IHBsbF9vZl90YWJsZSB7DQo+ICsJdW5zaWduZWQgbG9uZyBwcmF0ZTsN
Cj4gKwlzdHJ1Y3QgcGxsX2NmZyAqcGxsX2NmZ190YWJsZTsNCj4gK307DQo+ICsNCj4gK3N0cnVj
dCBwbGxfb2ZfZGF0YSB7DQo+ICsJc3RydWN0IHBsbF9vZl90YWJsZSAqcGxsX3RhYmxlOw0KPiAr
fTsNCj4gKw0KPiArc3RhdGljIHN0cnVjdCBwbGxfb2ZfZGF0YSBwZ3VfcGxsX2RhdGEgPSB7DQo+
ICsJLnBsbF90YWJsZSA9IChzdHJ1Y3QgcGxsX29mX3RhYmxlIFtdKXsNCj4gKwkJew0KPiArCQkJ
LnByYXRlID0gMjcwMDAwMDAsDQo+ICsJCQkucGxsX2NmZ190YWJsZSA9IChzdHJ1Y3QgcGxsX2Nm
ZyBbXSl7DQo+ICsJCQkJeyAyNTIwMDAwMCwgMSwgODQsIDkwIH0sDQo+ICsJCQkJeyA1MDAwMDAw
MCwgMSwgMTAwLCA1NCB9LA0KPiArCQkJCXsgNzQyNTAwMDAsIDEsIDQ0LCAxNiB9LA0KPiArCQkJ
CXsgfSwNCj4gKwkJCX0sDQo+ICsJCX0sDQo+ICsJCS8qIFVzZWQgYXMgbGlzdCBsaW1pdGVyICov
DQo+ICsJCXsgfSwNCj4gKwl9LA0KPiArfTsNCj4gKw0KPiArc3RhdGljIHN0cnVjdCBwbGxfb2Zf
ZGF0YSBhcmNfcGxsX2RhdGEgPSB7DQo+ICsJLnBsbF90YWJsZSA9IChzdHJ1Y3QgcGxsX29mX3Rh
YmxlIFtdKXsNCj4gKwkJew0KPiArCQkJLnByYXRlID0gMzMzMzMzMzMsDQo+ICsJCQkucGxsX2Nm
Z190YWJsZSA9IChzdHJ1Y3QgcGxsX2NmZyBbXSl7DQo+ICsJCQkJeyAzMzMzMzMzMyzCoMKgMSwg
MSzCoMKgMSB9LA0KPiArCQkJCXsgNTAwMDAwMDAswqDCoDEsIDMwLCAyMCB9LA0KPiArCQkJCXsg
NzUwMDAwMDAswqDCoDIsIDQ1LCAxMCB9LA0KPiArCQkJCXsgOTAwMDAwMDAswqDCoDIsIDU0LCAx
MCB9LA0KPiArCQkJCXsgMTAwMDAwMDAwLCAxLCAzMCwgMTAgfSwNCj4gKwkJCQl7IDEyNTAwMDAw
MCwgMiwgNDUsIDYgfSwNCj4gKwkJCQl7IH0sDQo+ICsJCQl9LA0KPiArCQl9LA0KPiArCQkvKiBV
c2VkIGFzIGxpc3QgbGltaXRlciAqLw0KPiArCQl7IH0sDQo+ICsJfSwNCj4gK307DQo+ICsNCj4g
K3N0cnVjdCBwbGxfY2xrIHsNCj4gKwl2b2lkIF9faW9tZW0gKmJhc2U7DQo+ICsJdm9pZCBfX2lv
bWVtICpsb2NrOw0KPiArCWNvbnN0IHN0cnVjdCBwbGxfb2ZfZGF0YSAqcGxsX2RhdGE7DQo+ICsJ
c3RydWN0IGNsa19odyBodzsNCj4gKwlzdHJ1Y3QgZGV2aWNlICpkZXY7DQo+ICt9Ow0KPiArDQo+
ICtzdGF0aWMgaW5saW5lIHZvaWQgcGxsX3dyaXRlKHN0cnVjdCBwbGxfY2xrICpjbGssIHVuc2ln
bmVkIGludCByZWcsDQo+ICsJCXVuc2lnbmVkIGludCB2YWwpDQo+ICt7DQo+ICsJaW93cml0ZTMy
KHZhbCwgY2xrLT5iYXNlICsgcmVnKTsNCj4gK30NCj4gKw0KPiArc3RhdGljIGlubGluZSB1MzIg
cGxsX3JlYWQoc3RydWN0IHBsbF9jbGsgKmNsaywNCj4gKwkJdW5zaWduZWQgaW50IHJlZykNCj4g
K3sNCj4gKwlyZXR1cm4gaW9yZWFkMzIoY2xrLT5iYXNlICsgcmVnKTsNCj4gK30NCj4gKw0KPiAr
c3RhdGljIGlubGluZSBzdHJ1Y3QgcGxsX2NsayAqdG9fcGxsX2NsayhzdHJ1Y3QgY2xrX2h3ICpo
dykNCj4gK3sNCj4gKwlyZXR1cm4gY29udGFpbmVyX29mKGh3LCBzdHJ1Y3QgcGxsX2NsaywgaHcp
Ow0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW5saW5lIHUzMiBkaXZfZ2V0X3ZhbHVlKHVuc2lnbmVk
IGludCByZWcpDQo+ICt7DQo+ICsJaWYgKFBMTF9SRUdfR0VUX0JZUEFTUyhyZWcpKQ0KPiArCQly
ZXR1cm4gMTsNCj4gKw0KPiArCXJldHVybiAoUExMX1JFR19HRVRfSElHSChyZWcpICsgUExMX1JF
R19HRVRfTE9XKHJlZykpOw0KPiArfQ0KPiArDQo+ICtzdGF0aWMgaW5saW5lIHUzMiBlbmNvZGVf
ZGl2KHVuc2lnbmVkIGludCBpZCwgaW50IHVwZCkNCj4gK3sNCj4gKwl1aW50MzJfdCBkaXYgPSAw
Ow0KPiArDQo+ICsJUExMX1JFR19TRVRfTE9XKGRpdiwgKGlkJTIgPT0gMCkgPyBpZCA+PiAxIDog
KGlkID4+IDEpICsgMSk7DQo+ICsJUExMX1JFR19TRVRfSElHSChkaXYsIGlkID4+IDEpOw0KPiAr
CVBMTF9SRUdfU0VUX0VER0UoZGl2LCBpZCUyKTsNCj4gKwlQTExfUkVHX1NFVF9CWVBBU1MoZGl2
LCBpZCA9PSAxID8gMSA6IDApOw0KPiArCVBMTF9SRUdfU0VUX05PVVBEKGRpdiwgIXVwZCk7DQo+
ICsNCj4gKwlyZXR1cm4gZGl2Ow0KPiArfQ0KPiArDQo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IHBs
bF9jZmcgKnBsbF9nZXRfY2ZnKHVuc2lnbmVkIGxvbmcgcHJhdGUsDQo+ICsJCWNvbnN0IHN0cnVj
dCBwbGxfb2ZfdGFibGUgKnBsbF90YWJsZSkNCj4gK3sNCj4gKwlpbnQgaTsNCj4gKw0KPiArCWZv
ciAoaSA9IDA7IHBsbF90YWJsZVtpXS5wcmF0ZSAhPSAwOyBpKyspDQo+ICsJCWlmIChwbGxfdGFi
bGVbaV0ucHJhdGUgPT0gcHJhdGUpDQo+ICsJCQlyZXR1cm4gcGxsX3RhYmxlW2ldLnBsbF9jZmdf
dGFibGU7DQo+ICsNCj4gKwlyZXR1cm4gTlVMTDsNCj4gK30NCj4gKw0KPiArc3RhdGljIHVuc2ln
bmVkIGxvbmcgcGxsX3JlY2FsY19yYXRlKHN0cnVjdCBjbGtfaHcgKmh3LA0KPiArCQkJdW5zaWdu
ZWQgbG9uZyBwYXJlbnRfcmF0ZSkNCj4gK3sNCj4gKwl1NjQgcmF0ZTsNCj4gKwl1MzIgaWRpdiwg
ZmJkaXYsIG9kaXY7DQo+ICsJc3RydWN0IHBsbF9jbGsgKmNsayA9IHRvX3BsbF9jbGsoaHcpOw0K
PiArDQo+ICsJaWRpdiA9IGRpdl9nZXRfdmFsdWUocGxsX3JlYWQoY2xrLCBQTExfUkVHX0lESVYp
KTsNCj4gKwlmYmRpdiA9IGRpdl9nZXRfdmFsdWUocGxsX3JlYWQoY2xrLCBQTExfUkVHX0ZCRElW
KSk7DQo+ICsJb2RpdiA9IGRpdl9nZXRfdmFsdWUocGxsX3JlYWQoY2xrLCBQTExfUkVHX09ESVYp
KTsNCj4gKw0KPiArCXJhdGUgPSAodTY0KXBhcmVudF9yYXRlICogZmJkaXY7DQo+ICsJZG9fZGl2
KHJhdGUsIGlkaXYgKiBvZGl2KTsNCj4gKw0KPiArCXJldHVybiAodW5zaWduZWQgbG9uZylyYXRl
Ow0KPiArfQ0KPiArDQo+ICtzdGF0aWMgbG9uZyBwbGxfcm91bmRfcmF0ZShzdHJ1Y3QgY2xrX2h3
ICpodywgdW5zaWduZWQgbG9uZyByYXRlLA0KPiArCQkJdW5zaWduZWQgbG9uZyAqcHJhdGUpDQo+
ICt7DQo+ICsJaW50IGk7DQo+ICsJbG9uZyBiZXN0X3JhdGU7DQo+ICsJc3RydWN0IHBsbF9jbGsg
KmNsayA9IHRvX3BsbF9jbGsoaHcpOw0KPiArCWNvbnN0IHN0cnVjdCBwbGxfY2ZnICpwbGxfY2Zn
ID0gcGxsX2dldF9jZmcoKnByYXRlLA0KPiArCQkJY2xrLT5wbGxfZGF0YS0+cGxsX3RhYmxlKTsN
Cj4gKw0KPiArCWlmICghcGxsX2NmZykgew0KPiArCQlkZXZfZXJyKGNsay0+ZGV2LCAiaW52YWxp
ZCBwYXJlbnQgcmF0ZT0lbGRcbiIsICpwcmF0ZSk7DQo+ICsJCXJldHVybiAtRUlOVkFMOw0KPiAr
CX0NCj4gKw0KPiArCWlmIChwbGxfY2ZnWzBdLnJhdGUgPT0gMCkNCj4gKwkJcmV0dXJuIC1FSU5W
QUw7DQo+ICsNCj4gKwliZXN0X3JhdGUgPSBwbGxfY2ZnWzBdLnJhdGU7DQo+ICsNCj4gKwlmb3Ig
KGkgPSAxOyBwbGxfY2ZnW2ldLnJhdGUgIT0gMDsgaSsrKSB7DQo+ICsJCWlmIChhYnMocmF0ZSAt
IHBsbF9jZmdbaV0ucmF0ZSkgPCBhYnMocmF0ZSAtIGJlc3RfcmF0ZSkpDQo+ICsJCQliZXN0X3Jh
dGUgPSBwbGxfY2ZnW2ldLnJhdGU7DQo+ICsJfQ0KPiArDQo+ICsJcmV0dXJuIGJlc3RfcmF0ZTsN
Cj4gK30NCj4gKw0KPiArc3RhdGljIGludCBwbGxfc2V0X3JhdGUoc3RydWN0IGNsa19odyAqaHcs
IHVuc2lnbmVkIGxvbmcgcmF0ZSwNCj4gKwkJCXVuc2lnbmVkIGxvbmcgcGFyZW50X3JhdGUpDQo+
ICt7DQo+ICsJaW50IGk7DQo+ICsJc3RydWN0IHBsbF9jbGsgKmNsayA9IHRvX3BsbF9jbGsoaHcp
Ow0KPiArCWNvbnN0IHN0cnVjdCBwbGxfY2ZnICpwbGxfY2ZnID0gcGxsX2dldF9jZmcocGFyZW50
X3JhdGUsDQo+ICsJCQljbGstPnBsbF9kYXRhLT5wbGxfdGFibGUpOw0KPiArDQo+ICsJaWYgKCFw
bGxfY2ZnKSB7DQo+ICsJCWRldl9lcnIoY2xrLT5kZXYsICJpbnZhbGlkIHBhcmVudCByYXRlPSVs
ZFxuIiwgcGFyZW50X3JhdGUpOw0KPiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gKwl9DQo+ICsNCj4g
Kwlmb3IgKGkgPSAwOyBwbGxfY2ZnW2ldLnJhdGUgIT0gMDsgaSsrKSB7DQo+ICsJCWlmIChwbGxf
Y2ZnW2ldLnJhdGUgPT0gcmF0ZSkgew0KPiArCQkJcGxsX3dyaXRlKGNsaywgUExMX1JFR19JRElW
LA0KPiArCQkJCQllbmNvZGVfZGl2KHBsbF9jZmdbaV0uaWRpdiwgMCkpOw0KPiArCQkJcGxsX3dy
aXRlKGNsaywgUExMX1JFR19GQkRJViwNCj4gKwkJCQkJZW5jb2RlX2RpdihwbGxfY2ZnW2ldLmZi
ZGl2LCAwKSk7DQo+ICsJCQlwbGxfd3JpdGUoY2xrLCBQTExfUkVHX09ESVYsDQo+ICsJCQkJCWVu
Y29kZV9kaXYocGxsX2NmZ1tpXS5vZGl2LCAxKSk7DQo+ICsNCj4gKwkJCS8qDQo+ICsJCQnCoCog
V2FpdCB1bnRpbCBDR1UgcmVsb2Nrcy4NCj4gKwkJCcKgKiBJZiBhZnRlciB0aW1lb3V0IENHVSBp
cyB1bmxvY2tlZCB5ZXQgcmV0dXJuIGVycm9yDQo+ICsJCQnCoCovDQo+ICsJCQl1ZGVsYXkoUExM
X01BWF9MT0NLX1RJTUUpOw0KPiArCQkJaWYgKGlvcmVhZDMyKGNsay0+bG9jaykgJiBQTExfTE9D
SykNCj4gKwkJCQlyZXR1cm4gMDsNCj4gKwkJCWVsc2UNCj4gKwkJCQlyZXR1cm4gLUVUSU1FRE9V
VDsNCj4gKwkJfQ0KPiArCX0NCj4gKw0KPiArCWRldl9lcnIoY2xrLT5kZXYsICJpbnZhbGlkIHJh
dGU9JWxkLCBwYXJlbnRfcmF0ZT0lbGRcbiIsIHJhdGUsDQo+ICsJCQlwYXJlbnRfcmF0ZSk7DQo+
ICsJcmV0dXJuIC1FSU5WQUw7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgY2xr
X29wcyBwbGxfb3BzID0gew0KPiArCS5yZWNhbGNfcmF0ZSA9IHBsbF9yZWNhbGNfcmF0ZSwNCj4g
Kwkucm91bmRfcmF0ZSA9IHBsbF9yb3VuZF9yYXRlLA0KPiArCS5zZXRfcmF0ZSA9IHBsbF9zZXRf
cmF0ZSwNCj4gK307DQo+ICsNCj4gK3N0YXRpYyBpbnQgcGxsX2Nsa19wcm9iZShzdHJ1Y3QgcGxh
dGZvcm1fZGV2aWNlICpwZGV2KQ0KPiArew0KPiArCXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwZGV2
LT5kZXY7DQo+ICsJY29uc3QgY2hhciAqcGFyZW50X25hbWU7DQo+ICsJc3RydWN0IGNsayAqY2xr
Ow0KPiArCXN0cnVjdCBwbGxfY2xrICpwbGxfY2xrOw0KPiArCXN0cnVjdCByZXNvdXJjZSAqbWVt
Ow0KPiArCXN0cnVjdCBjbGtfaW5pdF9kYXRhIGluaXQgPSB7IH07DQo+ICsNCj4gKwlwbGxfY2xr
ID0gZGV2bV9remFsbG9jKGRldiwgc2l6ZW9mKCpwbGxfY2xrKSwgR0ZQX0tFUk5FTCk7DQo+ICsJ
aWYgKCFwbGxfY2xrKQ0KPiArCQlyZXR1cm4gLUVOT01FTTsNCj4gKw0KPiArCW1lbSA9IHBsYXRm
b3JtX2dldF9yZXNvdXJjZShwZGV2LCBJT1JFU09VUkNFX01FTSwgMCk7DQo+ICsJcGxsX2Nsay0+
YmFzZSA9IGRldm1faW9yZW1hcF9yZXNvdXJjZShkZXYsIG1lbSk7DQo+ICsJaWYgKElTX0VSUihw
bGxfY2xrLT5iYXNlKSkNCj4gKwkJcmV0dXJuIFBUUl9FUlIocGxsX2Nsay0+YmFzZSk7DQo+ICsN
Cj4gKwltZW0gPSBwbGF0Zm9ybV9nZXRfcmVzb3VyY2UocGRldiwgSU9SRVNPVVJDRV9NRU0sIDEp
Ow0KPiArCXBsbF9jbGstPmxvY2sgPSBkZXZtX2lvcmVtYXBfcmVzb3VyY2UoZGV2LCBtZW0pOw0K
PiArCWlmIChJU19FUlIocGxsX2Nsay0+bG9jaykpDQo+ICsJCXJldHVybiBQVFJfRVJSKHBsbF9j
bGstPmJhc2UpOw0KPiArDQo+ICsJaW5pdC5uYW1lID0gZGV2LT5vZl9ub2RlLT5uYW1lOw0KPiAr
CWluaXQub3BzID0gJnBsbF9vcHM7DQo+ICsJcGFyZW50X25hbWUgPSBvZl9jbGtfZ2V0X3BhcmVu
dF9uYW1lKGRldi0+b2Zfbm9kZSwgMCk7DQo+ICsJaW5pdC5wYXJlbnRfbmFtZXMgPSAmcGFyZW50
X25hbWU7DQo+ICsJaW5pdC5udW1fcGFyZW50cyA9IDE7DQo+ICsJcGxsX2Nsay0+aHcuaW5pdCA9
ICZpbml0Ow0KPiArCXBsbF9jbGstPmRldiA9IGRldjsNCj4gKwlwbGxfY2xrLT5wbGxfZGF0YSA9
IG9mX2RldmljZV9nZXRfbWF0Y2hfZGF0YShkZXYpOw0KPiArDQo+ICsJaWYgKCFwbGxfY2xrLT5w
bGxfZGF0YSkgew0KPiArCQlkZXZfZXJyKGRldiwgIk5vIE9GIG1hdGNoIGRhdGEgcHJvdmlkZWRc
biIpOw0KPiArCQkJcmV0dXJuIC1FSU5WQUw7DQo+ICsJfQ0KPiArDQo+ICsJY2xrID0gZGV2bV9j
bGtfcmVnaXN0ZXIoZGV2LCAmcGxsX2Nsay0+aHcpOw0KPiArCWlmIChJU19FUlIoY2xrKSkgew0K
PiArCQlkZXZfZXJyKGRldiwgImZhaWxlZCB0byByZWdpc3RlciAlcyBjbG9jayAoJWxkKVxuIiwN
Cj4gKwkJCQlpbml0Lm5hbWUsIFBUUl9FUlIoY2xrKSk7DQo+ICsJCXJldHVybiBQVFJfRVJSKGNs
ayk7DQo+ICsJfQ0KPiArDQo+ICsJcmV0dXJuIG9mX2Nsa19hZGRfcHJvdmlkZXIoZGV2LT5vZl9u
b2RlLCBvZl9jbGtfc3JjX3NpbXBsZV9nZXQsIGNsayk7DQo+ICt9DQo+ICsNCj4gK3N0YXRpYyBp
bnQgcGxsX2Nsa19yZW1vdmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikNCj4gK3sNCj4g
KwlvZl9jbGtfZGVsX3Byb3ZpZGVyKHBkZXYtPmRldi5vZl9ub2RlKTsNCj4gKwlyZXR1cm4gMDsN
Cj4gK30NCj4gKw0KPiArc3RhdGljIHZvaWQgX19pbml0IG9mX3BsbF9jbGtfc2V0dXAoc3RydWN0
IGRldmljZV9ub2RlICpub2RlKQ0KPiArew0KPiArCWNvbnN0IGNoYXIgKnBhcmVudF9uYW1lOw0K
PiArCXN0cnVjdCBjbGsgKmNsazsNCj4gKwlzdHJ1Y3QgcGxsX2NsayAqcGxsX2NsazsNCj4gKwlz
dHJ1Y3QgY2xrX2luaXRfZGF0YSBpbml0ID0geyB9Ow0KPiArDQo+ICsJcGxsX2NsayA9IGt6YWxs
b2Moc2l6ZW9mKCpwbGxfY2xrKSwgR0ZQX0tFUk5FTCk7DQo+ICsJaWYgKCFwbGxfY2xrKQ0KPiAr
CQlyZXR1cm47DQo+ICsNCj4gKwlwbGxfY2xrLT5iYXNlID0gb2ZfaW9tYXAobm9kZSwgMCk7DQo+
ICsJaWYgKCFwbGxfY2xrLT5iYXNlKSB7DQo+ICsJCXByX2VycigiZmFpbGVkIHRvIG1hcCBwbGwg
ZGl2IHJlZ2lzdGVyc1xuIik7DQo+ICsJCWlvdW5tYXAocGxsX2Nsay0+YmFzZSk7DQo+ICsJCXJl
dHVybjsNCj4gKwl9DQo+ICsNCj4gKwlwbGxfY2xrLT5sb2NrID0gb2ZfaW9tYXAobm9kZSwgMSk7
DQo+ICsJaWYgKCFwbGxfY2xrLT5sb2NrKSB7DQo+ICsJCXByX2VycigiZmFpbGVkIHRvIG1hcCBw
bGwgbG9jayByZWdpc3RlclxuIik7DQo+ICsJCWlvdW5tYXAocGxsX2Nsay0+bG9jayk7DQo+ICsJ
CXJldHVybjsNCj4gKwl9DQo+ICsNCj4gKwlpbml0Lm5hbWUgPSBub2RlLT5uYW1lOw0KPiArCWlu
aXQub3BzID0gJnBsbF9vcHM7DQo+ICsJcGFyZW50X25hbWUgPSBvZl9jbGtfZ2V0X3BhcmVudF9u
YW1lKG5vZGUsIDApOw0KPiArCWluaXQucGFyZW50X25hbWVzID0gJnBhcmVudF9uYW1lOw0KPiAr
CWluaXQubnVtX3BhcmVudHMgPSBwYXJlbnRfbmFtZSA/IDEgOiAwOw0KPiArCXBsbF9jbGstPmh3
LmluaXQgPSAmaW5pdDsNCj4gKwlwbGxfY2xrLT5wbGxfZGF0YSA9ICZhcmNfcGxsX2RhdGE7DQo+
ICsNCj4gKwljbGsgPSBjbGtfcmVnaXN0ZXIoTlVMTCwgJnBsbF9jbGstPmh3KTsNCj4gKwlpZiAo
SVNfRVJSKGNsaykpIHsNCj4gKwkJcHJfZXJyKCJmYWlsZWQgdG8gcmVnaXN0ZXIgJXMgY2xvY2sg
KCVsZClcbiIsDQo+ICsJCQkJbm9kZS0+bmFtZSwgUFRSX0VSUihjbGspKTsNCj4gKwkJa2ZyZWUo
cGxsX2Nsayk7DQo+ICsJCXJldHVybjsNCj4gKwl9DQo+ICsNCj4gKwlvZl9jbGtfYWRkX3Byb3Zp
ZGVyKG5vZGUsIG9mX2Nsa19zcmNfc2ltcGxlX2dldCwgY2xrKTsNCj4gK30NCj4gKw0KPiArQ0xL
X09GX0RFQ0xBUkUoYXhzMTB4X3BsbF9jbG9jaywgInNucHMsYXhzMTB4LWFyYy1wbGwtY2xvY2si
LCBvZl9wbGxfY2xrX3NldHVwKTsNCj4gKw0KPiArc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZp
Y2VfaWQgcGxsX2Nsa19pZFtdID0gew0KPiArCXsgLmNvbXBhdGlibGUgPSAic25wcyxheHMxMHgt
YXJjLXBsbC1jbG9jayIsIC5kYXRhID0gJmFyY19wbGxfZGF0YX0sDQo+ICsJeyAuY29tcGF0aWJs
ZSA9ICJzbnBzLGF4czEweC1wZ3UtcGxsLWNsb2NrIiwgLmRhdGEgPSAmcGd1X3BsbF9kYXRhfSwN
Cj4gKwl7IH0sDQo+ICt9Ow0KPiArTU9EVUxFX0RFVklDRV9UQUJMRShvZiwgcGxsX2Nsa19pZCk7
DQo+ICsNCj4gK3N0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIHBsbF9jbGtfZHJpdmVyID0g
ew0KPiArCS5kcml2ZXIgPSB7DQo+ICsJCS5uYW1lID0gImF4czEweC1wbGwtY2xvY2siLA0KPiAr
CQkub2ZfbWF0Y2hfdGFibGUgPSBwbGxfY2xrX2lkLA0KPiArCX0sDQo+ICsJLnByb2JlID0gcGxs
X2Nsa19wcm9iZSwNCj4gKwkucmVtb3ZlID0gcGxsX2Nsa19yZW1vdmUsDQo+ICt9Ow0KPiArYnVp
bHRpbl9wbGF0Zm9ybV9kcml2ZXIocGxsX2Nsa19kcml2ZXIpOw0KPiArDQo+ICtNT0RVTEVfQVVU
SE9SKCJWbGFkIFpha2hhcm92IDx2emFraGFyQHN5bm9wc3lzLmNvbT4iKTsNCj4gK01PRFVMRV9E
RVNDUklQVElPTigiU3lub3BzeXMgQVhTMTBYIFNEUCBHZW5lcmljIFBMTCBDbG9jayBEcml2ZXIi
KTsNCj4gK01PRFVMRV9MSUNFTlNFKCJHUEwgdjIiKTsNCg0KTWF5YmUgeW91IGhhdmUgYW55IGNv
bW1lbnRzIG9yIHJlbWFya3MgYWJvdXQgdGhpcyBwYXRjaD8gQW5kIGlmIHlvdSBkb24ndCBjb3Vs
ZCB5b3UgcGxlYXNlIGFwcGx5IGl0Lg0KDQpUaGFua3MhDQoNCi0tIA0KQmVzdCByZWdhcmRzLA0K
VmxhZCBaYWtoYXJvdiA8dnpha2hhckBzeW5vcHN5cy5jb20+
WARNING: multiple messages have this Message-ID (diff)
From: Vladislav.Zakharov@synopsys.com (Vlad Zakharov)
To: linux-snps-arc@lists.infradead.org
Subject: [PATCH v2] clk/axs10x: introduce AXS10X pll driver
Date: Fri, 3 Mar 2017 13:18:34 +0000 [thread overview]
Message-ID: <1488547113.2557.44.camel@synopsys.com> (raw)
In-Reply-To: <1487682670-4164-1-git-send-email-vzakhar@synopsys.com>
Hi Michael, Stephen,
On Tue, 2017-02-21@16:11 +0300, Vlad Zakharov wrote:
> AXS10X boards manages it's clocks using various PLLs. These PLL has same
> dividers and corresponding control registers mapped to different addresses.
> So we add one common driver for such PLLs.
>
> Each PLL on AXS10X board consist of three dividers: IDIV, FBDIV and
> ODIV. Output clock value is managed using these dividers.
>
> We add pre-defined tables with supported rate values and appropriate
> configurations of IDIV, FBDIV and ODIV for each value.
>
> As of today we add support for PLLs that generate clock for the
> following devices:
> ?* ARC core on AXC CPU tiles.
> ?* ARC PGU on ARC SDP Mainboard.
> and more to come later.
>
> Acked-by: Rob Herring <robh at kernel.org>
> Signed-off-by: Vlad Zakharov <vzakhar at synopsys.com>
> Signed-off-by: Jose Abreu <joabreu at synopsys.com>
> Cc: Michael Turquette <mturquette at baylibre.com>
> Cc: Stephen Boyd <sboyd at codeaurora.org>
> Cc: Mark Rutland <mark.rutland at arm.com>
> ---
> Cc: Rob Herring <robh at kernel.org>
> Changes v1..v2
> ?- Replace '_' with '-' in device tree nodes
>
> ?.../devicetree/bindings/clock/snps,pll-clock.txt???|??28 ++
> ?MAINTAINERS????????????????????????????????????????|???6 +
> ?drivers/clk/axs10x/Makefile????????????????????????|???1 +
> ?drivers/clk/axs10x/pll_clock.c?????????????????????| 384 +++++++++++++++++++++
> ?4 files changed, 419 insertions(+)
> ?create mode 100644 Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> ?create mode 100644 drivers/clk/axs10x/pll_clock.c
>
> diff --git a/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> new file mode 100644
> index 0000000..5706246
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> @@ -0,0 +1,28 @@
> +Binding for the AXS10X Generic PLL clock
> +
> +This binding uses the common clock binding[1].
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
> +
> +Required properties:
> +- compatible: should be "snps,axs10x-<name>-pll-clock"
> +??"snps,axs10x-arc-pll-clock"
> +??"snps,axs10x-pgu-pll-clock"
> +- reg: should always contain 2 pairs address - length: first for PLL config
> +registers and second for corresponding LOCK CGU register.
> +- clocks: shall be the input parent clock phandle for the PLL.
> +- #clock-cells: from common clock binding; Should always be set to 0.
> +
> +Example:
> + input-clk: input-clk {
> + clock-frequency = <33333333>;
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + };
> +
> + core-clk: core-clk at 80 {
> + compatible = "snps,axs10x-arc-pll-clock";
> + reg = <0x80 0x10 0x100 0x10>;
> + #clock-cells = <0>;
> + clocks = <&input-clk>;
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3960e7f..5805833 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11910,6 +11910,12 @@ F: arch/arc/plat-axs10x
> ?F: arch/arc/boot/dts/ax*
> ?F: Documentation/devicetree/bindings/arc/axs10*
> ?
> +SYNOPSYS ARC SDP clock driver
> +M: Vlad Zakharov <vzakhar at synopsys.com>
> +S: Supported
> +F: drivers/clk/axs10x/*
> +F: Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> +
> ?SYSTEM CONFIGURATION (SYSCON)
> ?M: Lee Jones <lee.jones at linaro.org>
> ?M: Arnd Bergmann <arnd at arndb.de>
> diff --git a/drivers/clk/axs10x/Makefile b/drivers/clk/axs10x/Makefile
> index 01996b8..d747dea 100644
> --- a/drivers/clk/axs10x/Makefile
> +++ b/drivers/clk/axs10x/Makefile
> @@ -1 +1,2 @@
> ?obj-y += i2s_pll_clock.o
> +obj-y += pll_clock.o
> diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c
> new file mode 100644
> index 0000000..784a0a2
> --- /dev/null
> +++ b/drivers/clk/axs10x/pll_clock.c
> @@ -0,0 +1,384 @@
> +/*
> + * Synopsys AXS10X SDP Generic PLL clock driver
> + *
> + * Copyright (C) 2017 Synopsys
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/device.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +
> +/* PLL registers addresses */
> +#define PLL_REG_IDIV 0x0
> +#define PLL_REG_FBDIV 0x4
> +#define PLL_REG_ODIV 0x8
> +
> +/*
> + * Bit fields of the PLL IDIV/FBDIV/ODIV registers:
> + *??________________________________________________________________________
> + * |31????????????????15|????14????|???13???|??12??|11?????????6|5?????????0|
> + * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--|
> + * |____________________|__________|________|______|____________|___________|
> + *
> + * Following macros detirmine the way of access to these registers
> + * They should be set up only using the macros.
> + * reg should be and uint32_t variable.
> + */
> +
> +#define PLL_REG_GET_LOW(reg) \
> + (((reg) & (0x3F << 0)) >> 0)
> +#define PLL_REG_GET_HIGH(reg) \
> + (((reg) & (0x3F << 6)) >> 6)
> +#define PLL_REG_GET_EDGE(reg) \
> + (((reg) & (BIT(12))) ? 1 : 0)
> +#define PLL_REG_GET_BYPASS(reg) \
> + (((reg) & (BIT(13))) ? 1 : 0)
> +#define PLL_REG_GET_NOUPD(reg) \
> + (((reg) & (BIT(14))) ? 1 : 0)
> +#define PLL_REG_GET_PAD(reg) \
> + (((reg) & (0x1FFFF << 15)) >> 15)
> +
> +#define PLL_REG_SET_LOW(reg, value) \
> + { reg |= (((value) & 0x3F) << 0); }
> +#define PLL_REG_SET_HIGH(reg, value) \
> + { reg |= (((value) & 0x3F) << 6); }
> +#define PLL_REG_SET_EDGE(reg, value) \
> + { reg |= (((value) & 0x01) << 12); }
> +#define PLL_REG_SET_BYPASS(reg, value) \
> + { reg |= (((value) & 0x01) << 13); }
> +#define PLL_REG_SET_NOUPD(reg, value) \
> + { reg |= (((value) & 0x01) << 14); }
> +#define PLL_REG_SET_PAD(reg, value) \
> + { reg |= (((value) & 0x1FFFF) << 15); }
> +
> +#define PLL_LOCK 0x1
> +#define PLL_MAX_LOCK_TIME 100 /* 100 us */
> +
> +struct pll_cfg {
> + u32 rate;
> + u32 idiv;
> + u32 fbdiv;
> + u32 odiv;
> +};
> +
> +struct pll_of_table {
> + unsigned long prate;
> + struct pll_cfg *pll_cfg_table;
> +};
> +
> +struct pll_of_data {
> + struct pll_of_table *pll_table;
> +};
> +
> +static struct pll_of_data pgu_pll_data = {
> + .pll_table = (struct pll_of_table []){
> + {
> + .prate = 27000000,
> + .pll_cfg_table = (struct pll_cfg []){
> + { 25200000, 1, 84, 90 },
> + { 50000000, 1, 100, 54 },
> + { 74250000, 1, 44, 16 },
> + { },
> + },
> + },
> + /* Used as list limiter */
> + { },
> + },
> +};
> +
> +static struct pll_of_data arc_pll_data = {
> + .pll_table = (struct pll_of_table []){
> + {
> + .prate = 33333333,
> + .pll_cfg_table = (struct pll_cfg []){
> + { 33333333,??1, 1,??1 },
> + { 50000000,??1, 30, 20 },
> + { 75000000,??2, 45, 10 },
> + { 90000000,??2, 54, 10 },
> + { 100000000, 1, 30, 10 },
> + { 125000000, 2, 45, 6 },
> + { },
> + },
> + },
> + /* Used as list limiter */
> + { },
> + },
> +};
> +
> +struct pll_clk {
> + void __iomem *base;
> + void __iomem *lock;
> + const struct pll_of_data *pll_data;
> + struct clk_hw hw;
> + struct device *dev;
> +};
> +
> +static inline void pll_write(struct pll_clk *clk, unsigned int reg,
> + unsigned int val)
> +{
> + iowrite32(val, clk->base + reg);
> +}
> +
> +static inline u32 pll_read(struct pll_clk *clk,
> + unsigned int reg)
> +{
> + return ioread32(clk->base + reg);
> +}
> +
> +static inline struct pll_clk *to_pll_clk(struct clk_hw *hw)
> +{
> + return container_of(hw, struct pll_clk, hw);
> +}
> +
> +static inline u32 div_get_value(unsigned int reg)
> +{
> + if (PLL_REG_GET_BYPASS(reg))
> + return 1;
> +
> + return (PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg));
> +}
> +
> +static inline u32 encode_div(unsigned int id, int upd)
> +{
> + uint32_t div = 0;
> +
> + PLL_REG_SET_LOW(div, (id%2 == 0) ? id >> 1 : (id >> 1) + 1);
> + PLL_REG_SET_HIGH(div, id >> 1);
> + PLL_REG_SET_EDGE(div, id%2);
> + PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0);
> + PLL_REG_SET_NOUPD(div, !upd);
> +
> + return div;
> +}
> +
> +static const struct pll_cfg *pll_get_cfg(unsigned long prate,
> + const struct pll_of_table *pll_table)
> +{
> + int i;
> +
> + for (i = 0; pll_table[i].prate != 0; i++)
> + if (pll_table[i].prate == prate)
> + return pll_table[i].pll_cfg_table;
> +
> + return NULL;
> +}
> +
> +static unsigned long pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + u64 rate;
> + u32 idiv, fbdiv, odiv;
> + struct pll_clk *clk = to_pll_clk(hw);
> +
> + idiv = div_get_value(pll_read(clk, PLL_REG_IDIV));
> + fbdiv = div_get_value(pll_read(clk, PLL_REG_FBDIV));
> + odiv = div_get_value(pll_read(clk, PLL_REG_ODIV));
> +
> + rate = (u64)parent_rate * fbdiv;
> + do_div(rate, idiv * odiv);
> +
> + return (unsigned long)rate;
> +}
> +
> +static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *prate)
> +{
> + int i;
> + long best_rate;
> + struct pll_clk *clk = to_pll_clk(hw);
> + const struct pll_cfg *pll_cfg = pll_get_cfg(*prate,
> + clk->pll_data->pll_table);
> +
> + if (!pll_cfg) {
> + dev_err(clk->dev, "invalid parent rate=%ld\n", *prate);
> + return -EINVAL;
> + }
> +
> + if (pll_cfg[0].rate == 0)
> + return -EINVAL;
> +
> + best_rate = pll_cfg[0].rate;
> +
> + for (i = 1; pll_cfg[i].rate != 0; i++) {
> + if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
> + best_rate = pll_cfg[i].rate;
> + }
> +
> + return best_rate;
> +}
> +
> +static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + int i;
> + struct pll_clk *clk = to_pll_clk(hw);
> + const struct pll_cfg *pll_cfg = pll_get_cfg(parent_rate,
> + clk->pll_data->pll_table);
> +
> + if (!pll_cfg) {
> + dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate);
> + return -EINVAL;
> + }
> +
> + for (i = 0; pll_cfg[i].rate != 0; i++) {
> + if (pll_cfg[i].rate == rate) {
> + pll_write(clk, PLL_REG_IDIV,
> + encode_div(pll_cfg[i].idiv, 0));
> + pll_write(clk, PLL_REG_FBDIV,
> + encode_div(pll_cfg[i].fbdiv, 0));
> + pll_write(clk, PLL_REG_ODIV,
> + encode_div(pll_cfg[i].odiv, 1));
> +
> + /*
> + ?* Wait until CGU relocks.
> + ?* If after timeout CGU is unlocked yet return error
> + ?*/
> + udelay(PLL_MAX_LOCK_TIME);
> + if (ioread32(clk->lock) & PLL_LOCK)
> + return 0;
> + else
> + return -ETIMEDOUT;
> + }
> + }
> +
> + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
> + parent_rate);
> + return -EINVAL;
> +}
> +
> +static const struct clk_ops pll_ops = {
> + .recalc_rate = pll_recalc_rate,
> + .round_rate = pll_round_rate,
> + .set_rate = pll_set_rate,
> +};
> +
> +static int pll_clk_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + const char *parent_name;
> + struct clk *clk;
> + struct pll_clk *pll_clk;
> + struct resource *mem;
> + struct clk_init_data init = { };
> +
> + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
> + if (!pll_clk)
> + return -ENOMEM;
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + pll_clk->base = devm_ioremap_resource(dev, mem);
> + if (IS_ERR(pll_clk->base))
> + return PTR_ERR(pll_clk->base);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + pll_clk->lock = devm_ioremap_resource(dev, mem);
> + if (IS_ERR(pll_clk->lock))
> + return PTR_ERR(pll_clk->base);
> +
> + init.name = dev->of_node->name;
> + init.ops = &pll_ops;
> + parent_name = of_clk_get_parent_name(dev->of_node, 0);
> + init.parent_names = &parent_name;
> + init.num_parents = 1;
> + pll_clk->hw.init = &init;
> + pll_clk->dev = dev;
> + pll_clk->pll_data = of_device_get_match_data(dev);
> +
> + if (!pll_clk->pll_data) {
> + dev_err(dev, "No OF match data provided\n");
> + return -EINVAL;
> + }
> +
> + clk = devm_clk_register(dev, &pll_clk->hw);
> + if (IS_ERR(clk)) {
> + dev_err(dev, "failed to register %s clock (%ld)\n",
> + init.name, PTR_ERR(clk));
> + return PTR_ERR(clk);
> + }
> +
> + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, clk);
> +}
> +
> +static int pll_clk_remove(struct platform_device *pdev)
> +{
> + of_clk_del_provider(pdev->dev.of_node);
> + return 0;
> +}
> +
> +static void __init of_pll_clk_setup(struct device_node *node)
> +{
> + const char *parent_name;
> + struct clk *clk;
> + struct pll_clk *pll_clk;
> + struct clk_init_data init = { };
> +
> + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
> + if (!pll_clk)
> + return;
> +
> + pll_clk->base = of_iomap(node, 0);
> + if (!pll_clk->base) {
> + pr_err("failed to map pll div registers\n");
> + iounmap(pll_clk->base);
> + return;
> + }
> +
> + pll_clk->lock = of_iomap(node, 1);
> + if (!pll_clk->lock) {
> + pr_err("failed to map pll lock register\n");
> + iounmap(pll_clk->lock);
> + return;
> + }
> +
> + init.name = node->name;
> + init.ops = &pll_ops;
> + parent_name = of_clk_get_parent_name(node, 0);
> + init.parent_names = &parent_name;
> + init.num_parents = parent_name ? 1 : 0;
> + pll_clk->hw.init = &init;
> + pll_clk->pll_data = &arc_pll_data;
> +
> + clk = clk_register(NULL, &pll_clk->hw);
> + if (IS_ERR(clk)) {
> + pr_err("failed to register %s clock (%ld)\n",
> + node->name, PTR_ERR(clk));
> + kfree(pll_clk);
> + return;
> + }
> +
> + of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +}
> +
> +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", of_pll_clk_setup);
> +
> +static const struct of_device_id pll_clk_id[] = {
> + { .compatible = "snps,axs10x-arc-pll-clock", .data = &arc_pll_data},
> + { .compatible = "snps,axs10x-pgu-pll-clock", .data = &pgu_pll_data},
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, pll_clk_id);
> +
> +static struct platform_driver pll_clk_driver = {
> + .driver = {
> + .name = "axs10x-pll-clock",
> + .of_match_table = pll_clk_id,
> + },
> + .probe = pll_clk_probe,
> + .remove = pll_clk_remove,
> +};
> +builtin_platform_driver(pll_clk_driver);
> +
> +MODULE_AUTHOR("Vlad Zakharov <vzakhar at synopsys.com>");
> +MODULE_DESCRIPTION("Synopsys AXS10X SDP Generic PLL Clock Driver");
> +MODULE_LICENSE("GPL v2");
Maybe you have any comments or remarks about this patch? And if you don't could you please apply it.
Thanks!
--
Best regards,
Vlad Zakharov <vzakhar at synopsys.com>
WARNING: multiple messages have this Message-ID (diff)
From: Vlad Zakharov <Vladislav.Zakharov-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
Cc: "linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org"
<linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
"mturquette-rdvid1DuHRBWk0Htik3J/w@public.gmane.org"
<mturquette-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>,
Jose Abreu <Jose.Abreu-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>,
"devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org"
<devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
"linux-snps-arc-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org"
<linux-snps-arc-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>,
"mark.rutland-5wv7dgnIgG8@public.gmane.org"
<mark.rutland-5wv7dgnIgG8@public.gmane.org>,
"robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org"
<robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
"linux-clk-u79uwXL29TY76Z2rM5mHXA@public.gmane.org"
<linux-clk-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
"sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org"
<sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Subject: Re: [PATCH v2] clk/axs10x: introduce AXS10X pll driver
Date: Fri, 3 Mar 2017 13:18:34 +0000 [thread overview]
Message-ID: <1488547113.2557.44.camel@synopsys.com> (raw)
In-Reply-To: <1487682670-4164-1-git-send-email-vzakhar-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 15218 bytes --]
Hi Michael, Stephen,
On Tue, 2017-02-21 at 16:11 +0300, Vlad Zakharov wrote:
> AXS10X boards manages it's clocks using various PLLs. These PLL has same
> dividers and corresponding control registers mapped to different addresses.
> So we add one common driver for such PLLs.
>
> Each PLL on AXS10X board consist of three dividers: IDIV, FBDIV and
> ODIV. Output clock value is managed using these dividers.
>
> We add pre-defined tables with supported rate values and appropriate
> configurations of IDIV, FBDIV and ODIV for each value.
>
> As of today we add support for PLLs that generate clock for the
> following devices:
> Â * ARC core on AXC CPU tiles.
> Â * ARC PGU on ARC SDP Mainboard.
> and more to come later.
>
> Acked-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Vlad Zakharov <vzakhar@synopsys.com>
> Signed-off-by: Jose Abreu <joabreu@synopsys.com>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> ---
> Cc: Rob Herring <robh@kernel.org>
> Changes v1..v2
> Â - Replace '_' with '-' in device tree nodes
>
>  .../devicetree/bindings/clock/snps,pll-clock.txt   |  28 ++
> Â MAINTAINERSÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |Â Â Â 6 +
>  drivers/clk/axs10x/Makefile                        |   1 +
>  drivers/clk/axs10x/pll_clock.c                     | 384 +++++++++++++++++++++
> Â 4 files changed, 419 insertions(+)
> Â create mode 100644 Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> Â create mode 100644 drivers/clk/axs10x/pll_clock.c
>
> diff --git a/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> new file mode 100644
> index 0000000..5706246
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> @@ -0,0 +1,28 @@
> +Binding for the AXS10X Generic PLL clock
> +
> +This binding uses the common clock binding[1].
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
> +
> +Required properties:
> +- compatible: should be "snps,axs10x-<name>-pll-clock"
> +Â Â "snps,axs10x-arc-pll-clock"
> +Â Â "snps,axs10x-pgu-pll-clock"
> +- reg: should always contain 2 pairs address - length: first for PLL config
> +registers and second for corresponding LOCK CGU register.
> +- clocks: shall be the input parent clock phandle for the PLL.
> +- #clock-cells: from common clock binding; Should always be set to 0.
> +
> +Example:
> + input-clk: input-clk {
> + clock-frequency = <33333333>;
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + };
> +
> + core-clk: core-clk@80 {
> + compatible = "snps,axs10x-arc-pll-clock";
> + reg = <0x80 0x10 0x100 0x10>;
> + #clock-cells = <0>;
> + clocks = <&input-clk>;
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3960e7f..5805833 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11910,6 +11910,12 @@ F: arch/arc/plat-axs10x
> Â F: arch/arc/boot/dts/ax*
> Â F: Documentation/devicetree/bindings/arc/axs10*
> Â
> +SYNOPSYS ARC SDP clock driver
> +M: Vlad Zakharov <vzakhar@synopsys.com>
> +S: Supported
> +F: drivers/clk/axs10x/*
> +F: Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> +
> Â SYSTEM CONFIGURATION (SYSCON)
> Â M: Lee Jones <lee.jones@linaro.org>
> Â M: Arnd Bergmann <arnd@arndb.de>
> diff --git a/drivers/clk/axs10x/Makefile b/drivers/clk/axs10x/Makefile
> index 01996b8..d747dea 100644
> --- a/drivers/clk/axs10x/Makefile
> +++ b/drivers/clk/axs10x/Makefile
> @@ -1 +1,2 @@
> Â obj-y += i2s_pll_clock.o
> +obj-y += pll_clock.o
> diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c
> new file mode 100644
> index 0000000..784a0a2
> --- /dev/null
> +++ b/drivers/clk/axs10x/pll_clock.c
> @@ -0,0 +1,384 @@
> +/*
> + * Synopsys AXS10X SDP Generic PLL clock driver
> + *
> + * Copyright (C) 2017 Synopsys
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/device.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +
> +/* PLL registers addresses */
> +#define PLL_REG_IDIV 0x0
> +#define PLL_REG_FBDIV 0x4
> +#define PLL_REG_ODIV 0x8
> +
> +/*
> + * Bit fields of the PLL IDIV/FBDIV/ODIV registers:
> + *Â Â ________________________________________________________________________
> + * |31Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â 15|Â Â Â Â 14Â Â Â Â |Â Â Â 13Â Â Â |Â Â 12Â Â |11Â Â Â Â Â Â Â Â Â 6|5Â Â Â Â Â Â Â Â Â 0|
> + * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--|
> + * |____________________|__________|________|______|____________|___________|
> + *
> + * Following macros detirmine the way of access to these registers
> + * They should be set up only using the macros.
> + * reg should be and uint32_t variable.
> + */
> +
> +#define PLL_REG_GET_LOW(reg) \
> + (((reg) & (0x3F << 0)) >> 0)
> +#define PLL_REG_GET_HIGH(reg) \
> + (((reg) & (0x3F << 6)) >> 6)
> +#define PLL_REG_GET_EDGE(reg) \
> + (((reg) & (BIT(12))) ? 1 : 0)
> +#define PLL_REG_GET_BYPASS(reg) \
> + (((reg) & (BIT(13))) ? 1 : 0)
> +#define PLL_REG_GET_NOUPD(reg) \
> + (((reg) & (BIT(14))) ? 1 : 0)
> +#define PLL_REG_GET_PAD(reg) \
> + (((reg) & (0x1FFFF << 15)) >> 15)
> +
> +#define PLL_REG_SET_LOW(reg, value) \
> + { reg |= (((value) & 0x3F) << 0); }
> +#define PLL_REG_SET_HIGH(reg, value) \
> + { reg |= (((value) & 0x3F) << 6); }
> +#define PLL_REG_SET_EDGE(reg, value) \
> + { reg |= (((value) & 0x01) << 12); }
> +#define PLL_REG_SET_BYPASS(reg, value) \
> + { reg |= (((value) & 0x01) << 13); }
> +#define PLL_REG_SET_NOUPD(reg, value) \
> + { reg |= (((value) & 0x01) << 14); }
> +#define PLL_REG_SET_PAD(reg, value) \
> + { reg |= (((value) & 0x1FFFF) << 15); }
> +
> +#define PLL_LOCK 0x1
> +#define PLL_MAX_LOCK_TIME 100 /* 100 us */
> +
> +struct pll_cfg {
> + u32 rate;
> + u32 idiv;
> + u32 fbdiv;
> + u32 odiv;
> +};
> +
> +struct pll_of_table {
> + unsigned long prate;
> + struct pll_cfg *pll_cfg_table;
> +};
> +
> +struct pll_of_data {
> + struct pll_of_table *pll_table;
> +};
> +
> +static struct pll_of_data pgu_pll_data = {
> + .pll_table = (struct pll_of_table []){
> + {
> + .prate = 27000000,
> + .pll_cfg_table = (struct pll_cfg []){
> + { 25200000, 1, 84, 90 },
> + { 50000000, 1, 100, 54 },
> + { 74250000, 1, 44, 16 },
> + { },
> + },
> + },
> + /* Used as list limiter */
> + { },
> + },
> +};
> +
> +static struct pll_of_data arc_pll_data = {
> + .pll_table = (struct pll_of_table []){
> + {
> + .prate = 33333333,
> + .pll_cfg_table = (struct pll_cfg []){
> + { 33333333,  1, 1,  1 },
> + { 50000000,  1, 30, 20 },
> + { 75000000,  2, 45, 10 },
> + { 90000000,  2, 54, 10 },
> + { 100000000, 1, 30, 10 },
> + { 125000000, 2, 45, 6 },
> + { },
> + },
> + },
> + /* Used as list limiter */
> + { },
> + },
> +};
> +
> +struct pll_clk {
> + void __iomem *base;
> + void __iomem *lock;
> + const struct pll_of_data *pll_data;
> + struct clk_hw hw;
> + struct device *dev;
> +};
> +
> +static inline void pll_write(struct pll_clk *clk, unsigned int reg,
> + unsigned int val)
> +{
> + iowrite32(val, clk->base + reg);
> +}
> +
> +static inline u32 pll_read(struct pll_clk *clk,
> + unsigned int reg)
> +{
> + return ioread32(clk->base + reg);
> +}
> +
> +static inline struct pll_clk *to_pll_clk(struct clk_hw *hw)
> +{
> + return container_of(hw, struct pll_clk, hw);
> +}
> +
> +static inline u32 div_get_value(unsigned int reg)
> +{
> + if (PLL_REG_GET_BYPASS(reg))
> + return 1;
> +
> + return (PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg));
> +}
> +
> +static inline u32 encode_div(unsigned int id, int upd)
> +{
> + uint32_t div = 0;
> +
> + PLL_REG_SET_LOW(div, (id%2 == 0) ? id >> 1 : (id >> 1) + 1);
> + PLL_REG_SET_HIGH(div, id >> 1);
> + PLL_REG_SET_EDGE(div, id%2);
> + PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0);
> + PLL_REG_SET_NOUPD(div, !upd);
> +
> + return div;
> +}
> +
> +static const struct pll_cfg *pll_get_cfg(unsigned long prate,
> + const struct pll_of_table *pll_table)
> +{
> + int i;
> +
> + for (i = 0; pll_table[i].prate != 0; i++)
> + if (pll_table[i].prate == prate)
> + return pll_table[i].pll_cfg_table;
> +
> + return NULL;
> +}
> +
> +static unsigned long pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + u64 rate;
> + u32 idiv, fbdiv, odiv;
> + struct pll_clk *clk = to_pll_clk(hw);
> +
> + idiv = div_get_value(pll_read(clk, PLL_REG_IDIV));
> + fbdiv = div_get_value(pll_read(clk, PLL_REG_FBDIV));
> + odiv = div_get_value(pll_read(clk, PLL_REG_ODIV));
> +
> + rate = (u64)parent_rate * fbdiv;
> + do_div(rate, idiv * odiv);
> +
> + return (unsigned long)rate;
> +}
> +
> +static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *prate)
> +{
> + int i;
> + long best_rate;
> + struct pll_clk *clk = to_pll_clk(hw);
> + const struct pll_cfg *pll_cfg = pll_get_cfg(*prate,
> + clk->pll_data->pll_table);
> +
> + if (!pll_cfg) {
> + dev_err(clk->dev, "invalid parent rate=%ld\n", *prate);
> + return -EINVAL;
> + }
> +
> + if (pll_cfg[0].rate == 0)
> + return -EINVAL;
> +
> + best_rate = pll_cfg[0].rate;
> +
> + for (i = 1; pll_cfg[i].rate != 0; i++) {
> + if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
> + best_rate = pll_cfg[i].rate;
> + }
> +
> + return best_rate;
> +}
> +
> +static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + int i;
> + struct pll_clk *clk = to_pll_clk(hw);
> + const struct pll_cfg *pll_cfg = pll_get_cfg(parent_rate,
> + clk->pll_data->pll_table);
> +
> + if (!pll_cfg) {
> + dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate);
> + return -EINVAL;
> + }
> +
> + for (i = 0; pll_cfg[i].rate != 0; i++) {
> + if (pll_cfg[i].rate == rate) {
> + pll_write(clk, PLL_REG_IDIV,
> + encode_div(pll_cfg[i].idiv, 0));
> + pll_write(clk, PLL_REG_FBDIV,
> + encode_div(pll_cfg[i].fbdiv, 0));
> + pll_write(clk, PLL_REG_ODIV,
> + encode_div(pll_cfg[i].odiv, 1));
> +
> + /*
> + Â * Wait until CGU relocks.
> + Â * If after timeout CGU is unlocked yet return error
> + Â */
> + udelay(PLL_MAX_LOCK_TIME);
> + if (ioread32(clk->lock) & PLL_LOCK)
> + return 0;
> + else
> + return -ETIMEDOUT;
> + }
> + }
> +
> + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
> + parent_rate);
> + return -EINVAL;
> +}
> +
> +static const struct clk_ops pll_ops = {
> + .recalc_rate = pll_recalc_rate,
> + .round_rate = pll_round_rate,
> + .set_rate = pll_set_rate,
> +};
> +
> +static int pll_clk_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + const char *parent_name;
> + struct clk *clk;
> + struct pll_clk *pll_clk;
> + struct resource *mem;
> + struct clk_init_data init = { };
> +
> + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
> + if (!pll_clk)
> + return -ENOMEM;
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + pll_clk->base = devm_ioremap_resource(dev, mem);
> + if (IS_ERR(pll_clk->base))
> + return PTR_ERR(pll_clk->base);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + pll_clk->lock = devm_ioremap_resource(dev, mem);
> + if (IS_ERR(pll_clk->lock))
> + return PTR_ERR(pll_clk->base);
> +
> + init.name = dev->of_node->name;
> + init.ops = &pll_ops;
> + parent_name = of_clk_get_parent_name(dev->of_node, 0);
> + init.parent_names = &parent_name;
> + init.num_parents = 1;
> + pll_clk->hw.init = &init;
> + pll_clk->dev = dev;
> + pll_clk->pll_data = of_device_get_match_data(dev);
> +
> + if (!pll_clk->pll_data) {
> + dev_err(dev, "No OF match data provided\n");
> + return -EINVAL;
> + }
> +
> + clk = devm_clk_register(dev, &pll_clk->hw);
> + if (IS_ERR(clk)) {
> + dev_err(dev, "failed to register %s clock (%ld)\n",
> + init.name, PTR_ERR(clk));
> + return PTR_ERR(clk);
> + }
> +
> + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, clk);
> +}
> +
> +static int pll_clk_remove(struct platform_device *pdev)
> +{
> + of_clk_del_provider(pdev->dev.of_node);
> + return 0;
> +}
> +
> +static void __init of_pll_clk_setup(struct device_node *node)
> +{
> + const char *parent_name;
> + struct clk *clk;
> + struct pll_clk *pll_clk;
> + struct clk_init_data init = { };
> +
> + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
> + if (!pll_clk)
> + return;
> +
> + pll_clk->base = of_iomap(node, 0);
> + if (!pll_clk->base) {
> + pr_err("failed to map pll div registers\n");
> + iounmap(pll_clk->base);
> + return;
> + }
> +
> + pll_clk->lock = of_iomap(node, 1);
> + if (!pll_clk->lock) {
> + pr_err("failed to map pll lock register\n");
> + iounmap(pll_clk->lock);
> + return;
> + }
> +
> + init.name = node->name;
> + init.ops = &pll_ops;
> + parent_name = of_clk_get_parent_name(node, 0);
> + init.parent_names = &parent_name;
> + init.num_parents = parent_name ? 1 : 0;
> + pll_clk->hw.init = &init;
> + pll_clk->pll_data = &arc_pll_data;
> +
> + clk = clk_register(NULL, &pll_clk->hw);
> + if (IS_ERR(clk)) {
> + pr_err("failed to register %s clock (%ld)\n",
> + node->name, PTR_ERR(clk));
> + kfree(pll_clk);
> + return;
> + }
> +
> + of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +}
> +
> +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", of_pll_clk_setup);
> +
> +static const struct of_device_id pll_clk_id[] = {
> + { .compatible = "snps,axs10x-arc-pll-clock", .data = &arc_pll_data},
> + { .compatible = "snps,axs10x-pgu-pll-clock", .data = &pgu_pll_data},
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, pll_clk_id);
> +
> +static struct platform_driver pll_clk_driver = {
> + .driver = {
> + .name = "axs10x-pll-clock",
> + .of_match_table = pll_clk_id,
> + },
> + .probe = pll_clk_probe,
> + .remove = pll_clk_remove,
> +};
> +builtin_platform_driver(pll_clk_driver);
> +
> +MODULE_AUTHOR("Vlad Zakharov <vzakhar@synopsys.com>");
> +MODULE_DESCRIPTION("Synopsys AXS10X SDP Generic PLL Clock Driver");
> +MODULE_LICENSE("GPL v2");
Maybe you have any comments or remarks about this patch? And if you don't could you please apply it.
Thanks!
--
Best regards,
Vlad Zakharov <vzakhar@synopsys.com>N§²æìr¸yúèØb²X¬¶Ç§vØ^)Þº{.nÇ+·zøzÚÞz)í
æèw*\x1fjg¬±¨\x1e¶Ý¢j.ïÛ°\½½MúgjÌæa×\x02' ©Þ¢¸\f¢·¦j:+v¨wèjØm¶ÿ¾\a«êçzZ+ùÝ¢j"ú!¶i
WARNING: multiple messages have this Message-ID (diff)
From: Vlad Zakharov <Vladislav.Zakharov@synopsys.com>
To: Michael Turquette <mturquette@baylibre.com>,
Stephen Boyd <sboyd@codeaurora.org>
Cc: "linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"mturquette@baylibre.com" <mturquette@baylibre.com>,
Jose Abreu <Jose.Abreu@synopsys.com>,
"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
"linux-snps-arc@lists.infradead.org"
<linux-snps-arc@lists.infradead.org>,
"mark.rutland@arm.com" <mark.rutland@arm.com>,
"robh@kernel.org" <robh@kernel.org>,
"linux-clk@vger.kernel.org" <linux-clk@vger.kernel.org>,
"sboyd@codeaurora.org" <sboyd@codeaurora.org>
Subject: Re: [PATCH v2] clk/axs10x: introduce AXS10X pll driver
Date: Fri, 3 Mar 2017 13:18:34 +0000 [thread overview]
Message-ID: <1488547113.2557.44.camel@synopsys.com> (raw)
In-Reply-To: <1487682670-4164-1-git-send-email-vzakhar@synopsys.com>
Hi Michael, Stephen,
On Tue, 2017-02-21 at 16:11 +0300, Vlad Zakharov wrote:
> AXS10X boards manages it's clocks using various PLLs. These PLL has same
> dividers and corresponding control registers mapped to different addresses.
> So we add one common driver for such PLLs.
>
> Each PLL on AXS10X board consist of three dividers: IDIV, FBDIV and
> ODIV. Output clock value is managed using these dividers.
>
> We add pre-defined tables with supported rate values and appropriate
> configurations of IDIV, FBDIV and ODIV for each value.
>
> As of today we add support for PLLs that generate clock for the
> following devices:
> * ARC core on AXC CPU tiles.
> * ARC PGU on ARC SDP Mainboard.
> and more to come later.
>
> Acked-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Vlad Zakharov <vzakhar@synopsys.com>
> Signed-off-by: Jose Abreu <joabreu@synopsys.com>
> Cc: Michael Turquette <mturquette@baylibre.com>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> ---
> Cc: Rob Herring <robh@kernel.org>
> Changes v1..v2
> - Replace '_' with '-' in device tree nodes
>
> .../devicetree/bindings/clock/snps,pll-clock.txt | 28 ++
> MAINTAINERS | 6 +
> drivers/clk/axs10x/Makefile | 1 +
> drivers/clk/axs10x/pll_clock.c | 384 +++++++++++++++++++++
> 4 files changed, 419 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> create mode 100644 drivers/clk/axs10x/pll_clock.c
>
> diff --git a/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> new file mode 100644
> index 0000000..5706246
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> @@ -0,0 +1,28 @@
> +Binding for the AXS10X Generic PLL clock
> +
> +This binding uses the common clock binding[1].
> +
> +[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
> +
> +Required properties:
> +- compatible: should be "snps,axs10x-<name>-pll-clock"
> + "snps,axs10x-arc-pll-clock"
> + "snps,axs10x-pgu-pll-clock"
> +- reg: should always contain 2 pairs address - length: first for PLL config
> +registers and second for corresponding LOCK CGU register.
> +- clocks: shall be the input parent clock phandle for the PLL.
> +- #clock-cells: from common clock binding; Should always be set to 0.
> +
> +Example:
> + input-clk: input-clk {
> + clock-frequency = <33333333>;
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + };
> +
> + core-clk: core-clk@80 {
> + compatible = "snps,axs10x-arc-pll-clock";
> + reg = <0x80 0x10 0x100 0x10>;
> + #clock-cells = <0>;
> + clocks = <&input-clk>;
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 3960e7f..5805833 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11910,6 +11910,12 @@ F: arch/arc/plat-axs10x
> F: arch/arc/boot/dts/ax*
> F: Documentation/devicetree/bindings/arc/axs10*
>
> +SYNOPSYS ARC SDP clock driver
> +M: Vlad Zakharov <vzakhar@synopsys.com>
> +S: Supported
> +F: drivers/clk/axs10x/*
> +F: Documentation/devicetree/bindings/clock/snps,pll-clock.txt
> +
> SYSTEM CONFIGURATION (SYSCON)
> M: Lee Jones <lee.jones@linaro.org>
> M: Arnd Bergmann <arnd@arndb.de>
> diff --git a/drivers/clk/axs10x/Makefile b/drivers/clk/axs10x/Makefile
> index 01996b8..d747dea 100644
> --- a/drivers/clk/axs10x/Makefile
> +++ b/drivers/clk/axs10x/Makefile
> @@ -1 +1,2 @@
> obj-y += i2s_pll_clock.o
> +obj-y += pll_clock.o
> diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c
> new file mode 100644
> index 0000000..784a0a2
> --- /dev/null
> +++ b/drivers/clk/axs10x/pll_clock.c
> @@ -0,0 +1,384 @@
> +/*
> + * Synopsys AXS10X SDP Generic PLL clock driver
> + *
> + * Copyright (C) 2017 Synopsys
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/clk-provider.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/device.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +
> +/* PLL registers addresses */
> +#define PLL_REG_IDIV 0x0
> +#define PLL_REG_FBDIV 0x4
> +#define PLL_REG_ODIV 0x8
> +
> +/*
> + * Bit fields of the PLL IDIV/FBDIV/ODIV registers:
> + * ________________________________________________________________________
> + * |31 15| 14 | 13 | 12 |11 6|5 0|
> + * |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--|
> + * |____________________|__________|________|______|____________|___________|
> + *
> + * Following macros detirmine the way of access to these registers
> + * They should be set up only using the macros.
> + * reg should be and uint32_t variable.
> + */
> +
> +#define PLL_REG_GET_LOW(reg) \
> + (((reg) & (0x3F << 0)) >> 0)
> +#define PLL_REG_GET_HIGH(reg) \
> + (((reg) & (0x3F << 6)) >> 6)
> +#define PLL_REG_GET_EDGE(reg) \
> + (((reg) & (BIT(12))) ? 1 : 0)
> +#define PLL_REG_GET_BYPASS(reg) \
> + (((reg) & (BIT(13))) ? 1 : 0)
> +#define PLL_REG_GET_NOUPD(reg) \
> + (((reg) & (BIT(14))) ? 1 : 0)
> +#define PLL_REG_GET_PAD(reg) \
> + (((reg) & (0x1FFFF << 15)) >> 15)
> +
> +#define PLL_REG_SET_LOW(reg, value) \
> + { reg |= (((value) & 0x3F) << 0); }
> +#define PLL_REG_SET_HIGH(reg, value) \
> + { reg |= (((value) & 0x3F) << 6); }
> +#define PLL_REG_SET_EDGE(reg, value) \
> + { reg |= (((value) & 0x01) << 12); }
> +#define PLL_REG_SET_BYPASS(reg, value) \
> + { reg |= (((value) & 0x01) << 13); }
> +#define PLL_REG_SET_NOUPD(reg, value) \
> + { reg |= (((value) & 0x01) << 14); }
> +#define PLL_REG_SET_PAD(reg, value) \
> + { reg |= (((value) & 0x1FFFF) << 15); }
> +
> +#define PLL_LOCK 0x1
> +#define PLL_MAX_LOCK_TIME 100 /* 100 us */
> +
> +struct pll_cfg {
> + u32 rate;
> + u32 idiv;
> + u32 fbdiv;
> + u32 odiv;
> +};
> +
> +struct pll_of_table {
> + unsigned long prate;
> + struct pll_cfg *pll_cfg_table;
> +};
> +
> +struct pll_of_data {
> + struct pll_of_table *pll_table;
> +};
> +
> +static struct pll_of_data pgu_pll_data = {
> + .pll_table = (struct pll_of_table []){
> + {
> + .prate = 27000000,
> + .pll_cfg_table = (struct pll_cfg []){
> + { 25200000, 1, 84, 90 },
> + { 50000000, 1, 100, 54 },
> + { 74250000, 1, 44, 16 },
> + { },
> + },
> + },
> + /* Used as list limiter */
> + { },
> + },
> +};
> +
> +static struct pll_of_data arc_pll_data = {
> + .pll_table = (struct pll_of_table []){
> + {
> + .prate = 33333333,
> + .pll_cfg_table = (struct pll_cfg []){
> + { 33333333, 1, 1, 1 },
> + { 50000000, 1, 30, 20 },
> + { 75000000, 2, 45, 10 },
> + { 90000000, 2, 54, 10 },
> + { 100000000, 1, 30, 10 },
> + { 125000000, 2, 45, 6 },
> + { },
> + },
> + },
> + /* Used as list limiter */
> + { },
> + },
> +};
> +
> +struct pll_clk {
> + void __iomem *base;
> + void __iomem *lock;
> + const struct pll_of_data *pll_data;
> + struct clk_hw hw;
> + struct device *dev;
> +};
> +
> +static inline void pll_write(struct pll_clk *clk, unsigned int reg,
> + unsigned int val)
> +{
> + iowrite32(val, clk->base + reg);
> +}
> +
> +static inline u32 pll_read(struct pll_clk *clk,
> + unsigned int reg)
> +{
> + return ioread32(clk->base + reg);
> +}
> +
> +static inline struct pll_clk *to_pll_clk(struct clk_hw *hw)
> +{
> + return container_of(hw, struct pll_clk, hw);
> +}
> +
> +static inline u32 div_get_value(unsigned int reg)
> +{
> + if (PLL_REG_GET_BYPASS(reg))
> + return 1;
> +
> + return (PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg));
> +}
> +
> +static inline u32 encode_div(unsigned int id, int upd)
> +{
> + uint32_t div = 0;
> +
> + PLL_REG_SET_LOW(div, (id%2 == 0) ? id >> 1 : (id >> 1) + 1);
> + PLL_REG_SET_HIGH(div, id >> 1);
> + PLL_REG_SET_EDGE(div, id%2);
> + PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0);
> + PLL_REG_SET_NOUPD(div, !upd);
> +
> + return div;
> +}
> +
> +static const struct pll_cfg *pll_get_cfg(unsigned long prate,
> + const struct pll_of_table *pll_table)
> +{
> + int i;
> +
> + for (i = 0; pll_table[i].prate != 0; i++)
> + if (pll_table[i].prate == prate)
> + return pll_table[i].pll_cfg_table;
> +
> + return NULL;
> +}
> +
> +static unsigned long pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + u64 rate;
> + u32 idiv, fbdiv, odiv;
> + struct pll_clk *clk = to_pll_clk(hw);
> +
> + idiv = div_get_value(pll_read(clk, PLL_REG_IDIV));
> + fbdiv = div_get_value(pll_read(clk, PLL_REG_FBDIV));
> + odiv = div_get_value(pll_read(clk, PLL_REG_ODIV));
> +
> + rate = (u64)parent_rate * fbdiv;
> + do_div(rate, idiv * odiv);
> +
> + return (unsigned long)rate;
> +}
> +
> +static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *prate)
> +{
> + int i;
> + long best_rate;
> + struct pll_clk *clk = to_pll_clk(hw);
> + const struct pll_cfg *pll_cfg = pll_get_cfg(*prate,
> + clk->pll_data->pll_table);
> +
> + if (!pll_cfg) {
> + dev_err(clk->dev, "invalid parent rate=%ld\n", *prate);
> + return -EINVAL;
> + }
> +
> + if (pll_cfg[0].rate == 0)
> + return -EINVAL;
> +
> + best_rate = pll_cfg[0].rate;
> +
> + for (i = 1; pll_cfg[i].rate != 0; i++) {
> + if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
> + best_rate = pll_cfg[i].rate;
> + }
> +
> + return best_rate;
> +}
> +
> +static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + int i;
> + struct pll_clk *clk = to_pll_clk(hw);
> + const struct pll_cfg *pll_cfg = pll_get_cfg(parent_rate,
> + clk->pll_data->pll_table);
> +
> + if (!pll_cfg) {
> + dev_err(clk->dev, "invalid parent rate=%ld\n", parent_rate);
> + return -EINVAL;
> + }
> +
> + for (i = 0; pll_cfg[i].rate != 0; i++) {
> + if (pll_cfg[i].rate == rate) {
> + pll_write(clk, PLL_REG_IDIV,
> + encode_div(pll_cfg[i].idiv, 0));
> + pll_write(clk, PLL_REG_FBDIV,
> + encode_div(pll_cfg[i].fbdiv, 0));
> + pll_write(clk, PLL_REG_ODIV,
> + encode_div(pll_cfg[i].odiv, 1));
> +
> + /*
> + * Wait until CGU relocks.
> + * If after timeout CGU is unlocked yet return error
> + */
> + udelay(PLL_MAX_LOCK_TIME);
> + if (ioread32(clk->lock) & PLL_LOCK)
> + return 0;
> + else
> + return -ETIMEDOUT;
> + }
> + }
> +
> + dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
> + parent_rate);
> + return -EINVAL;
> +}
> +
> +static const struct clk_ops pll_ops = {
> + .recalc_rate = pll_recalc_rate,
> + .round_rate = pll_round_rate,
> + .set_rate = pll_set_rate,
> +};
> +
> +static int pll_clk_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + const char *parent_name;
> + struct clk *clk;
> + struct pll_clk *pll_clk;
> + struct resource *mem;
> + struct clk_init_data init = { };
> +
> + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
> + if (!pll_clk)
> + return -ENOMEM;
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + pll_clk->base = devm_ioremap_resource(dev, mem);
> + if (IS_ERR(pll_clk->base))
> + return PTR_ERR(pll_clk->base);
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + pll_clk->lock = devm_ioremap_resource(dev, mem);
> + if (IS_ERR(pll_clk->lock))
> + return PTR_ERR(pll_clk->base);
> +
> + init.name = dev->of_node->name;
> + init.ops = &pll_ops;
> + parent_name = of_clk_get_parent_name(dev->of_node, 0);
> + init.parent_names = &parent_name;
> + init.num_parents = 1;
> + pll_clk->hw.init = &init;
> + pll_clk->dev = dev;
> + pll_clk->pll_data = of_device_get_match_data(dev);
> +
> + if (!pll_clk->pll_data) {
> + dev_err(dev, "No OF match data provided\n");
> + return -EINVAL;
> + }
> +
> + clk = devm_clk_register(dev, &pll_clk->hw);
> + if (IS_ERR(clk)) {
> + dev_err(dev, "failed to register %s clock (%ld)\n",
> + init.name, PTR_ERR(clk));
> + return PTR_ERR(clk);
> + }
> +
> + return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, clk);
> +}
> +
> +static int pll_clk_remove(struct platform_device *pdev)
> +{
> + of_clk_del_provider(pdev->dev.of_node);
> + return 0;
> +}
> +
> +static void __init of_pll_clk_setup(struct device_node *node)
> +{
> + const char *parent_name;
> + struct clk *clk;
> + struct pll_clk *pll_clk;
> + struct clk_init_data init = { };
> +
> + pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
> + if (!pll_clk)
> + return;
> +
> + pll_clk->base = of_iomap(node, 0);
> + if (!pll_clk->base) {
> + pr_err("failed to map pll div registers\n");
> + iounmap(pll_clk->base);
> + return;
> + }
> +
> + pll_clk->lock = of_iomap(node, 1);
> + if (!pll_clk->lock) {
> + pr_err("failed to map pll lock register\n");
> + iounmap(pll_clk->lock);
> + return;
> + }
> +
> + init.name = node->name;
> + init.ops = &pll_ops;
> + parent_name = of_clk_get_parent_name(node, 0);
> + init.parent_names = &parent_name;
> + init.num_parents = parent_name ? 1 : 0;
> + pll_clk->hw.init = &init;
> + pll_clk->pll_data = &arc_pll_data;
> +
> + clk = clk_register(NULL, &pll_clk->hw);
> + if (IS_ERR(clk)) {
> + pr_err("failed to register %s clock (%ld)\n",
> + node->name, PTR_ERR(clk));
> + kfree(pll_clk);
> + return;
> + }
> +
> + of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +}
> +
> +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", of_pll_clk_setup);
> +
> +static const struct of_device_id pll_clk_id[] = {
> + { .compatible = "snps,axs10x-arc-pll-clock", .data = &arc_pll_data},
> + { .compatible = "snps,axs10x-pgu-pll-clock", .data = &pgu_pll_data},
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, pll_clk_id);
> +
> +static struct platform_driver pll_clk_driver = {
> + .driver = {
> + .name = "axs10x-pll-clock",
> + .of_match_table = pll_clk_id,
> + },
> + .probe = pll_clk_probe,
> + .remove = pll_clk_remove,
> +};
> +builtin_platform_driver(pll_clk_driver);
> +
> +MODULE_AUTHOR("Vlad Zakharov <vzakhar@synopsys.com>");
> +MODULE_DESCRIPTION("Synopsys AXS10X SDP Generic PLL Clock Driver");
> +MODULE_LICENSE("GPL v2");
Maybe you have any comments or remarks about this patch? And if you don't could you please apply it.
Thanks!
--
Best regards,
Vlad Zakharov <vzakhar@synopsys.com>
next prev parent reply other threads:[~2017-03-03 13:18 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-02-21 13:11 [PATCH v2] clk/axs10x: introduce AXS10X pll driver Vlad Zakharov
2017-02-21 13:11 ` Vlad Zakharov
2017-03-03 13:18 ` Vlad Zakharov [this message]
2017-03-03 13:18 ` Vlad Zakharov
2017-03-03 13:18 ` Vlad Zakharov
2017-03-03 13:18 ` Vlad Zakharov
2017-03-03 23:50 ` Stephen Boyd
2017-03-03 23:50 ` Stephen Boyd
2017-03-03 23:50 ` Stephen Boyd
2017-03-29 11:20 ` Vlad Zakharov
2017-03-29 11:20 ` Vlad Zakharov
2017-03-29 11:20 ` Vlad Zakharov
2017-03-29 11:20 ` Vlad Zakharov
2017-04-03 10:54 ` Jose Abreu
2017-04-03 10:54 ` Jose Abreu
2017-04-03 10:54 ` Jose Abreu
2017-04-05 1:35 ` Stephen Boyd
2017-04-05 1:35 ` Stephen Boyd
2017-04-05 1:35 ` Stephen Boyd
2017-04-05 16:06 ` Vlad Zakharov
2017-04-05 16:06 ` Vlad Zakharov
2017-04-05 16:06 ` Vlad Zakharov
2017-04-19 16:49 ` sboyd
2017-04-19 16:49 ` sboyd
2017-04-20 15:13 ` Vlad Zakharov
2017-04-20 15:13 ` Vlad Zakharov
2017-04-20 15:13 ` Vlad Zakharov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1488547113.2557.44.camel@synopsys.com \
--to=vladislav.zakharov@synopsys.com \
--cc=Jose.Abreu@synopsys.com \
--cc=devicetree@vger.kernel.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-snps-arc@lists.infradead.org \
--cc=mark.rutland@arm.com \
--cc=mturquette@baylibre.com \
--cc=robh@kernel.org \
--cc=sboyd@codeaurora.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.