Message ID | 6bf04ba1761f0692cb461558f0c8836f0d1f7ad8.1490595641.git.nandor.han@ge.com |
---|---|
State | New |
Headers | show |
On Mon, Mar 27, 2017 at 8:23 AM, Nandor Han <nandor.han@ge.com> wrote: > This is a simple driver that provides a /sys/class/gpio > interface for controlling and configuring the GPIO lines. Use the gpio tools in tools/gpio, use the characcter device. Do not use sysfs. Change this to reference the tools. > It does not provide support for chip select or interrupts. > > Signed-off-by: Nandor Han <nandor.han@ge.com> > Signed-off-by: Semi Malinen <semi.malinen@ge.com> (...) > +exar Exar Corporation Send this as a separate patch to the DT bindings maintainer (Rob Herring.) > +static int xra1403_get_byte(struct xra1403 *xra, unsigned int addr) > +{ > + return spi_w8r8(xra->spi, XRA_READ | (addr << 1)); > +} > + > +static int xra1403_get_bit(struct xra1403 *xra, unsigned int addr, > + unsigned int bit) > +{ > + int ret; > + > + ret = xra1403_get_byte(xra, addr + (bit > 7)); > + if (ret < 0) > + return ret; > + > + return !!(ret & BIT(bit % 8)); > +} This looks like it can use regmap-spi right off, do you agree? git grep devm_regmap_init_spi should give you some examples of how to use it. If it's not off-the shelf regmap drivers like drivers/iio/pressure/mpl115_spi.c give examples of how to make more elaborate custom SPI transfers with regmap. > +static int xra1403_set_bit(struct xra1403 *xra, unsigned int addr, > + unsigned int bit, int value) > +{ > + int ret; > + u8 mask; > + u8 tx[2]; > + > + addr += bit > 7; > + > + mutex_lock(&xra->lock); > + > + ret = xra1403_get_byte(xra, addr); > + if (ret < 0) > + goto out_unlock; > + > + mask = BIT(bit % 8); > + if (value) > + value = ret | mask; > + else > + value = ret & ~mask; > + > + if (value != ret) { > + tx[0] = addr << 1; > + tx[1] = value; > + ret = spi_write(xra->spi, tx, sizeof(tx)); > + } else { > + ret = 0; > + } > + > +out_unlock: > + mutex_unlock(&xra->lock); > + > + return ret; > +} Classical mask-and-set implementation right? With regmap this becomes simply regmap_update_bits(map, addr, mask, set) > +static int xra1403_probe(struct spi_device *spi) > +{ > + struct xra1403 *xra; > + struct gpio_desc *reset_gpio; > + > + xra = devm_kzalloc(&spi->dev, sizeof(*xra), GFP_KERNEL); > + if (!xra) > + return -ENOMEM; > + > + /* bring the chip out of reset */ > + reset_gpio = gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); > + if (IS_ERR(reset_gpio)) > + dev_warn(&spi->dev, "could not get reset-gpios\n"); > + else if (reset_gpio) > + gpiod_put(reset_gpio); I don't think you should put it, other than in the remove() function and in that case you need to have it in the state container. > + mutex_init(&xra->lock); > + > + xra->chip.direction_input = xra1403_direction_input; > + xra->chip.direction_output = xra1403_direction_output; Please implement .get_direction(). This is very nice to have. > +static int xra1403_remove(struct spi_device *spi) > +{ > + struct xra1403 *xra = spi_get_drvdata(spi); > + > + gpiochip_remove(&xra->chip); Use devm_gpiochip_add_data() and this remove is not needed at all. > +static int __init xra1403_init(void) > +{ > + return spi_register_driver(&xra1403_driver); > +} > + > +/* > + * register after spi postcore initcall and before > + * subsys initcalls that may rely on these GPIOs > + */ > +subsys_initcall(xra1403_init); > + > +static void __exit xra1403_exit(void) > +{ > + spi_unregister_driver(&xra1403_driver); > +} > +module_exit(xra1403_exit); This seems like tricksy. Just module_spi_driver() should be fine don't you think? Yours, Linus Walleij -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, Mar 27, 2017 at 09:23:00AM +0300, Nandor Han wrote: > This is a simple driver that provides a /sys/class/gpio > interface for controlling and configuring the GPIO lines. > It does not provide support for chip select or interrupts. > > Signed-off-by: Nandor Han <nandor.han@ge.com> > Signed-off-by: Semi Malinen <semi.malinen@ge.com> > --- > .../devicetree/bindings/vendor-prefixes.txt | 1 + This should go with the binding patch or by itself. > drivers/gpio/Kconfig | 5 + > drivers/gpio/Makefile | 1 + > drivers/gpio/gpio-xra1403.c | 252 +++++++++++++++++++++ > 4 files changed, 259 insertions(+) > create mode 100644 drivers/gpio/gpio-xra1403.c -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogTGludXMgV2FsbGVpaiBb bWFpbHRvOmxpbnVzLndhbGxlaWpAbGluYXJvLm9yZ10NCj4gU2VudDogMjkgTWFyY2ggMjAxNyAw NTowNw0KPiBUbzogSGFuLCBOYW5kb3IgKEdFIEhlYWx0aGNhcmUpIDxuYW5kb3IuaGFuQGdlLmNv bT4NCj4gQ2M6IEFsZXhhbmRyZSBDb3VyYm90IDxnbnVyb3VAZ21haWwuY29tPjsgUm9iIEhlcnJp bmcgPHJvYmgrZHRAa2VybmVsLm9yZz47IE1hcmsgUnV0bGFuZA0KPiA8bWFyay5ydXRsYW5kQGFy bS5jb20+OyBsaW51eC1ncGlvQHZnZXIua2VybmVsLm9yZzsgZGV2aWNldHJlZUB2Z2VyLmtlcm5l bC5vcmc7IGxpbnV4LWtlcm5lbEB2Z2VyLmtlcm5lbC5vcmc7DQo+IE1hbGluZW4sIFNlbWkgKEdF IEhlYWx0aGNhcmUpIDxzZW1pLm1hbGluZW5AZ2UuY29tPg0KPiBTdWJqZWN0OiBFWFQ6IFJlOiBb UEFUQ0ggMS8zXSBncGlvIC0gQWRkIEVYQVIgWFJBMTQwMyBTUEkgR1BJTyBleHBhbmRlciBkcml2 ZXINCj4gDQo+IE9uIE1vbiwgTWFyIDI3LCAyMDE3IGF0IDg6MjMgQU0sIE5hbmRvciBIYW4gPG5h bmRvci5oYW5AZ2UuY29tPiB3cm90ZToNCj4gDQo+ID4gVGhpcyBpcyBhIHNpbXBsZSBkcml2ZXIg dGhhdCBwcm92aWRlcyBhIC9zeXMvY2xhc3MvZ3Bpbw0KPiA+IGludGVyZmFjZSBmb3IgY29udHJv bGxpbmcgYW5kIGNvbmZpZ3VyaW5nIHRoZSBHUElPIGxpbmVzLg0KPiANCj4gVXNlIHRoZSBncGlv IHRvb2xzIGluIHRvb2xzL2dwaW8sIHVzZSB0aGUgY2hhcmFjY3RlciBkZXZpY2UuDQo+IERvIG5v dCB1c2Ugc3lzZnMuIENoYW5nZSB0aGlzIHRvIHJlZmVyZW5jZSB0aGUgdG9vbHMuDQo+IA0KPiA+ IEl0IGRvZXMgbm90IHByb3ZpZGUgc3VwcG9ydCBmb3IgY2hpcCBzZWxlY3Qgb3IgaW50ZXJydXB0 cy4NCj4gPg0KPiA+IFNpZ25lZC1vZmYtYnk6IE5hbmRvciBIYW4gPG5hbmRvci5oYW5AZ2UuY29t Pg0KPiA+IFNpZ25lZC1vZmYtYnk6IFNlbWkgTWFsaW5lbiA8c2VtaS5tYWxpbmVuQGdlLmNvbT4N Cj4gKC4uLikNCj4gPiArZXhhciAgIEV4YXIgQ29ycG9yYXRpb24NCj4gDQo+IFNlbmQgdGhpcyBh cyBhIHNlcGFyYXRlIHBhdGNoIHRvIHRoZSBEVCBiaW5kaW5ncyBtYWludGFpbmVyDQo+IChSb2Ig SGVycmluZy4pDQo+IA0KDQpPSy4gSSB3aWxsIGNyZWF0ZSBhIHNlcGFyYXRlIHBhdGNoIHdpdGgg dGhpcyBvbmUuIA0KSSBndWVzcyBpcyBub3QgYW4gaXNzdWUgdG8gc2VuZCBhbGwgdGhlIHBhdGNo ZXMgdG8gUm9iIGFzIHdlbGwuDQoNCjxzbmlwPg0KDQo+ID4gKw0KPiA+ICsgICAgICAgcmV0ID0g eHJhMTQwM19nZXRfYnl0ZSh4cmEsIGFkZHIgKyAoYml0ID4gNykpOw0KPiA+ICsgICAgICAgaWYg KHJldCA8IDApDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiByZXQ7DQo+ID4gKw0KPiA+ICsg ICAgICAgcmV0dXJuICEhKHJldCAmIEJJVChiaXQgJSA4KSk7DQo+ID4gK30NCj4gDQo+IFRoaXMg bG9va3MgbGlrZSBpdCBjYW4gdXNlIHJlZ21hcC1zcGkgcmlnaHQgb2ZmLCBkbyB5b3UgYWdyZWU/ DQo+IA0KDQpZZXMuIFVzaW5nIHJlZ21hcC1zcGkgd2lsbCBkZWZpbml0ZWx5IGltcHJvdmUgdGhl IGNvZGUgcmVhZGFiaWxpdHkgYW5kIHJlZHVjZSBib2lsZXJwbGF0ZS4NCkRvbmUuDQoNCj4gZ2l0 IGdyZXAgZGV2bV9yZWdtYXBfaW5pdF9zcGkNCj4gc2hvdWxkIGdpdmUgeW91IHNvbWUgZXhhbXBs ZXMgb2YgaG93IHRvIHVzZSBpdC4NCj4gDQo+IElmIGl0J3Mgbm90IG9mZi10aGUgc2hlbGYgcmVn bWFwIGRyaXZlcnMgbGlrZQ0KPiBkcml2ZXJzL2lpby9wcmVzc3VyZS9tcGwxMTVfc3BpLmMNCj4g Z2l2ZSBleGFtcGxlcyBvZiBob3cgdG8gbWFrZSBtb3JlIGVsYWJvcmF0ZSBjdXN0b20NCj4gU1BJ IHRyYW5zZmVycyB3aXRoIHJlZ21hcC4NCj4gDQoNClRoYW5rcywgSSBkaWQgY2hlY2sgb3RoZXIg ZHJpdmVycyBhcyBleGFtcGxlcy4gDQpOb3QgdGhhdCBJIG5lZWRlZCBmb3IgdGhpcyBkcml2ZXIs IGJ1dCAuLi5tcGwxMTVfc3BpLmMgZG9lc24ndCBzZWVtIHRvDQp1c2UgcmVnbWFwIChjaGVja2Vk IG9uIG5leHQtMjAxNzAzMjcpDQoNCjxzbmlwPg0KDQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKHZh bHVlICE9IHJldCkgew0KPiA+ICsgICAgICAgICAgICAgICB0eFswXSA9IGFkZHIgPDwgMTsNCj4g PiArICAgICAgICAgICAgICAgdHhbMV0gPSB2YWx1ZTsNCj4gPiArICAgICAgICAgICAgICAgcmV0 ID0gc3BpX3dyaXRlKHhyYS0+c3BpLCB0eCwgc2l6ZW9mKHR4KSk7DQo+ID4gKyAgICAgICB9IGVs c2Ugew0KPiA+ICsgICAgICAgICAgICAgICByZXQgPSAwOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsN Cj4gPiArb3V0X3VubG9jazoNCj4gPiArICAgICAgIG11dGV4X3VubG9jaygmeHJhLT5sb2NrKTsN Cj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gcmV0Ow0KPiA+ICt9DQo+IA0KPiBDbGFzc2ljYWwg bWFzay1hbmQtc2V0IGltcGxlbWVudGF0aW9uIHJpZ2h0Pw0KPiBXaXRoIHJlZ21hcCB0aGlzIGJl Y29tZXMgc2ltcGx5IHJlZ21hcF91cGRhdGVfYml0cyhtYXAsIGFkZHIsIG1hc2ssIHNldCkNCj4g DQoNClRydWUuIDopDQoNCjxzbmlwPg0KDQo+ID4gKyAgICAgICAvKiBicmluZyB0aGUgY2hpcCBv dXQgb2YgcmVzZXQgKi8NCj4gPiArICAgICAgIHJlc2V0X2dwaW8gPSBncGlvZF9nZXRfb3B0aW9u YWwoJnNwaS0+ZGV2LCAicmVzZXQiLCBHUElPRF9PVVRfTE9XKTsNCj4gPiArICAgICAgIGlmIChJ U19FUlIocmVzZXRfZ3BpbykpDQo+ID4gKyAgICAgICAgICAgICAgIGRldl93YXJuKCZzcGktPmRl diwgImNvdWxkIG5vdCBnZXQgcmVzZXQtZ3Bpb3NcbiIpOw0KPiA+ICsgICAgICAgZWxzZSBpZiAo cmVzZXRfZ3BpbykNCj4gPiArICAgICAgICAgICAgICAgZ3Bpb2RfcHV0KHJlc2V0X2dwaW8pOw0K PiANCj4gSSBkb24ndCB0aGluayB5b3Ugc2hvdWxkIHB1dCBpdCwgb3RoZXIgdGhhbiBpbiB0aGUg cmVtb3ZlKCkNCj4gZnVuY3Rpb24gYW5kIGluIHRoYXQgY2FzZSB5b3UgbmVlZCB0byBoYXZlIGl0 IGluIHRoZQ0KPiBzdGF0ZSBjb250YWluZXIuDQoNCkNhbiB5b3UgcGxlYXNlIGJlIG1vcmUgZXhw bGljaXQgaGVyZS4NCg0KQ3VycmVudGx5IEknbSB0cnlpbmcgdG8gYnJpbmcgdGhlIGRldmljZSBv dXQgZnJvbSByZXNldCBpbiBjYXNlIHJlc2V0IEdQSU8gaXMgcHJvdmlkZWQuDQpJIGRvbid0IHNl ZSBob3cgdGhpcyBjb3VsZCBiZSBkb25lIGluIHJlbW92ZSgpICA6KQ0KDQo+IA0KPiA+ICsgICAg ICAgbXV0ZXhfaW5pdCgmeHJhLT5sb2NrKTsNCj4gPiArDQo+ID4gKyAgICAgICB4cmEtPmNoaXAu ZGlyZWN0aW9uX2lucHV0ID0geHJhMTQwM19kaXJlY3Rpb25faW5wdXQ7DQo+ID4gKyAgICAgICB4 cmEtPmNoaXAuZGlyZWN0aW9uX291dHB1dCA9IHhyYTE0MDNfZGlyZWN0aW9uX291dHB1dDsNCj4g DQo+IFBsZWFzZSBpbXBsZW1lbnQgLmdldF9kaXJlY3Rpb24oKS4gVGhpcyBpcyB2ZXJ5IG5pY2Ug dG8gaGF2ZS4NCj4gDQoNCkRvbmUNCg0KPiA+ICtzdGF0aWMgaW50IHhyYTE0MDNfcmVtb3ZlKHN0 cnVjdCBzcGlfZGV2aWNlICpzcGkpDQo+ID4gK3sNCj4gPiArICAgICAgIHN0cnVjdCB4cmExNDAz ICp4cmEgPSBzcGlfZ2V0X2RydmRhdGEoc3BpKTsNCj4gPiArDQo+ID4gKyAgICAgICBncGlvY2hp cF9yZW1vdmUoJnhyYS0+Y2hpcCk7DQo+IA0KPiBVc2UgZGV2bV9ncGlvY2hpcF9hZGRfZGF0YSgp IGFuZCB0aGlzIHJlbW92ZSBpcyBub3QNCj4gbmVlZGVkIGF0IGFsbC4NCj4gDQoNClRydWUuIERv bmUNCg0KPHNuaXA+DQoNCj4gPiArc3Vic3lzX2luaXRjYWxsKHhyYTE0MDNfaW5pdCk7DQo+ID4g Kw0KPiA+ICtzdGF0aWMgdm9pZCBfX2V4aXQgeHJhMTQwM19leGl0KHZvaWQpDQo+ID4gK3sNCj4g PiArICAgICAgIHNwaV91bnJlZ2lzdGVyX2RyaXZlcigmeHJhMTQwM19kcml2ZXIpOw0KPiA+ICt9 DQo+ID4gK21vZHVsZV9leGl0KHhyYTE0MDNfZXhpdCk7DQo+IA0KPiBUaGlzIHNlZW1zIGxpa2Ug dHJpY2tzeS4gSnVzdCBtb2R1bGVfc3BpX2RyaXZlcigpDQo+IHNob3VsZCBiZSBmaW5lIGRvbid0 IHlvdSB0aGluaz8NCg0KWWVhaC4gVEJIIEkgZG9uJ3QgaGF2ZSBhIHN0cm9uZyByZWFzb24gd2h5 IG1vZHVsZV9zcGlfZHJpdmVyIGluaXQgbGV2ZWwgc2hvdWxkbid0IGJlIGVub3VnaC4gDQpEb25l Lg0KDQpSZWdhcmRzLA0KICAgIE5hbmRvcg0K -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Wed, Apr 5, 2017 at 3:24 PM, Han, Nandor (GE Healthcare) <nandor.han@ge.com> wrote: > [Me] >> > + /* bring the chip out of reset */ >> > + reset_gpio = gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); >> > + if (IS_ERR(reset_gpio)) >> > + dev_warn(&spi->dev, "could not get reset-gpios\n"); >> > + else if (reset_gpio) >> > + gpiod_put(reset_gpio); >> >> I don't think you should put it, other than in the remove() >> function and in that case you need to have it in the >> state container. > > Can you please be more explicit here. > > Currently I'm trying to bring the device out from reset in case reset GPIO is provided. > I don't see how this could be done in remove() :) If you issue gpiod_put() you release the GPIO hande so something else can go in and grab the GPIO and assert the reset. This is not what you want to make possible: you want to hold this gpiod handle as long as the driver is running. devm_gpiod_get_optional() will do the trick if you don't want to put the handle under explicit control. Yours, Linus Walleij -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogTGludXMgV2FsbGVpaiBb bWFpbHRvOmxpbnVzLndhbGxlaWpAbGluYXJvLm9yZ10NCj4gU2VudDogMDcgQXByaWwgMjAxNyAx MzowNw0KPiBUbzogSGFuLCBOYW5kb3IgKEdFIEhlYWx0aGNhcmUpIDxuYW5kb3IuaGFuQGdlLmNv bT4NCj4gQ2M6IEFsZXhhbmRyZSBDb3VyYm90IDxnbnVyb3VAZ21haWwuY29tPjsgUm9iIEhlcnJp bmcgPHJvYmgrZHRAa2VybmVsLm9yZz47IE1hcmsgUnV0bGFuZA0KPiA8bWFyay5ydXRsYW5kQGFy bS5jb20+OyBsaW51eC1ncGlvQHZnZXIua2VybmVsLm9yZzsgZGV2aWNldHJlZUB2Z2VyLmtlcm5l bC5vcmc7IGxpbnV4LWtlcm5lbEB2Z2VyLmtlcm5lbC5vcmc7DQo+IE1hbGluZW4sIFNlbWkgKEdF IEhlYWx0aGNhcmUpIDxzZW1pLm1hbGluZW5AZ2UuY29tPg0KPiBTdWJqZWN0OiBFWFQ6IFJlOiBb UEFUQ0ggMS8zXSBncGlvIC0gQWRkIEVYQVIgWFJBMTQwMyBTUEkgR1BJTyBleHBhbmRlciBkcml2 ZXINCj4gDQo+IE9uIFdlZCwgQXByIDUsIDIwMTcgYXQgMzoyNCBQTSwgSGFuLCBOYW5kb3IgKEdF IEhlYWx0aGNhcmUpDQo+IDxuYW5kb3IuaGFuQGdlLmNvbT4gd3JvdGU6DQo+ID4gW01lXQ0KPiA+ PiA+ICsgICAgICAgLyogYnJpbmcgdGhlIGNoaXAgb3V0IG9mIHJlc2V0ICovDQo+ID4+ID4gKyAg ICAgICByZXNldF9ncGlvID0gZ3Bpb2RfZ2V0X29wdGlvbmFsKCZzcGktPmRldiwgInJlc2V0Iiwg R1BJT0RfT1VUX0xPVyk7DQo+ID4+ID4gKyAgICAgICBpZiAoSVNfRVJSKHJlc2V0X2dwaW8pKQ0K PiA+PiA+ICsgICAgICAgICAgICAgICBkZXZfd2Fybigmc3BpLT5kZXYsICJjb3VsZCBub3QgZ2V0 IHJlc2V0LWdwaW9zXG4iKTsNCj4gPj4gPiArICAgICAgIGVsc2UgaWYgKHJlc2V0X2dwaW8pDQo+ ID4+ID4gKyAgICAgICAgICAgICAgIGdwaW9kX3B1dChyZXNldF9ncGlvKTsNCj4gPj4NCj4gPj4g SSBkb24ndCB0aGluayB5b3Ugc2hvdWxkIHB1dCBpdCwgb3RoZXIgdGhhbiBpbiB0aGUgcmVtb3Zl KCkNCj4gPj4gZnVuY3Rpb24gYW5kIGluIHRoYXQgY2FzZSB5b3UgbmVlZCB0byBoYXZlIGl0IGlu IHRoZQ0KPiA+PiBzdGF0ZSBjb250YWluZXIuDQo+ID4NCj4gPiBDYW4geW91IHBsZWFzZSBiZSBt b3JlIGV4cGxpY2l0IGhlcmUuDQo+ID4NCj4gPiBDdXJyZW50bHkgSSdtIHRyeWluZyB0byBicmlu ZyB0aGUgZGV2aWNlIG91dCBmcm9tIHJlc2V0IGluIGNhc2UgcmVzZXQgR1BJTyBpcyBwcm92aWRl ZC4NCj4gPiBJIGRvbid0IHNlZSBob3cgdGhpcyBjb3VsZCBiZSBkb25lIGluIHJlbW92ZSgpICA6 KQ0KPiANCj4gSWYgeW91IGlzc3VlIGdwaW9kX3B1dCgpIHlvdSByZWxlYXNlIHRoZSBHUElPIGhh bmRlIHNvIHNvbWV0aGluZyBlbHNlDQo+IGNhbiBnbyBpbiBhbmQgZ3JhYiB0aGUgR1BJTyBhbmQg YXNzZXJ0IHRoZSByZXNldC4NCj4gDQo+IFRoaXMgaXMgbm90IHdoYXQgeW91IHdhbnQgdG8gbWFr ZSBwb3NzaWJsZTogeW91IHdhbnQgdG8gaG9sZCB0aGlzIGdwaW9kIGhhbmRsZQ0KPiBhcyBsb25n IGFzIHRoZSBkcml2ZXIgaXMgcnVubmluZy4gZGV2bV9ncGlvZF9nZXRfb3B0aW9uYWwoKSB3aWxs IGRvIHRoZQ0KPiB0cmljayBpZiB5b3UgZG9uJ3Qgd2FudCB0byBwdXQgdGhlIGhhbmRsZSB1bmRl ciBleHBsaWNpdCBjb250cm9sLg0KPiANCg0KVGhhdCB3YXMgbXkgZmlyc3QgaW50ZW50aW9uIHRv IHJlbGVhc2UgdGhlIHJlc2V0IGxpbmUgaW4gY2FzZSBzb21lYm9keSBlbHNlIHdhbnRzIHRvIGNv bnRyb2wgaXQuIEkgZGlkIGl0DQpsaWtlIHRoYXQgYmVjYXVzZSB1c3VhbGx5IHJlc2V0IGxpbmUg Y29udHJvbHMgbXVsdGlwbGUgZGV2aWNlcyBhbmQgcHJvYmFibHkgc29tZSB1cHBlciBsYXllciB3 YW50cyB0bw0KY29udHJvbCB0aGF0LiANCg0KQWZ0ZXIgeW91ciBjb21tZW50IEkgZGlkIHNvbWUg YW5hbHlzaW5nIGFuZCBJIHdpbGwgZm9sbG93IHlvdXIgYWR2aWNlIGFuZCBjaGFuZ2UgdGhlIHJl c2V0IGxpbmUgaGFuZGxpbmcuIA0KT25jZSB0aGUgR1BJTyBpcyBwcm92aWRlZCB0byB0aGUgZHJp dmVyIHRoZSBkcml2ZXIgd2lsbCBvd24gaXQgYW5kIGJyaW5nIG91dCB0aGUgZGV2aWNlIGZyb20g cmVzZXQuIEluIGNhc2Ugbm90DQpwcm92aWRlZCB0aGUgcmVzZXQgbGluZSBpcyBzb21lYm9keSBl bHNlIHJlc3BvbnNpYmlsaXR5LiANCg0KVGhpcyB3YXkgd2UgYXJlIGFibGUgdG8gY292ZXIgbXVs dGlwbGUgdXNlLWNhc2VzLiANCg0KVGhhbmtzIExpbnVzLA0KTmFuZHkNCg0KPiBZb3VycywNCj4g TGludXMgV2FsbGVpag0K -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 0ad67d5..7ca9d41 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -103,6 +103,7 @@ ettus NI Ettus Research eukrea Eukréa Electromatique everest Everest Semiconductor Co. Ltd. everspin Everspin Technologies, Inc. +exar Exar Corporation excito Excito ezchip EZchip Semiconductor faraday Faraday Technology Corporation diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d6e3cfd..3a6c9a3 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1208,6 +1208,11 @@ config GPIO_PISOSR GPIO driver for SPI compatible parallel-in/serial-out shift registers. These are input only devices. +config GPIO_XRA1403 + tristate "EXAR XRA1403 16-bit GPIO expander" + help + GPIO driver for EXAR XRA1403 16-bit SPI-based GPIO expander. + endmenu menu "SPI or I2C GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index bd995dc..8f50844 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -139,6 +139,7 @@ obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o +obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c new file mode 100644 index 0000000..1b7138a8 --- /dev/null +++ b/drivers/gpio/gpio-xra1403.c @@ -0,0 +1,252 @@ +/* + * GPIO driver for EXAR XRA1403 16-bit GPIO expander + * + * Copyright (c) 2017, General Electric Company + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/bitops.h> +#include <linux/gpio/driver.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/spi/spi.h> + +/* XRA1403 registers */ +#define XRA_GSR 0x00 /* GPIO State */ +#define XRA_OCR 0x02 /* Output Control */ +#define XRA_GCR 0x06 /* GPIO Configuration */ + +/* SPI headers */ +#define XRA_READ 0x80 /* read bit of the SPI command byte */ + +struct xra1403 { + struct mutex lock; + struct gpio_chip chip; + struct spi_device *spi; +}; + +static int xra1403_get_byte(struct xra1403 *xra, unsigned int addr) +{ + return spi_w8r8(xra->spi, XRA_READ | (addr << 1)); +} + +static int xra1403_get_bit(struct xra1403 *xra, unsigned int addr, + unsigned int bit) +{ + int ret; + + ret = xra1403_get_byte(xra, addr + (bit > 7)); + if (ret < 0) + return ret; + + return !!(ret & BIT(bit % 8)); +} + +static int xra1403_set_bit(struct xra1403 *xra, unsigned int addr, + unsigned int bit, int value) +{ + int ret; + u8 mask; + u8 tx[2]; + + addr += bit > 7; + + mutex_lock(&xra->lock); + + ret = xra1403_get_byte(xra, addr); + if (ret < 0) + goto out_unlock; + + mask = BIT(bit % 8); + if (value) + value = ret | mask; + else + value = ret & ~mask; + + if (value != ret) { + tx[0] = addr << 1; + tx[1] = value; + ret = spi_write(xra->spi, tx, sizeof(tx)); + } else { + ret = 0; + } + +out_unlock: + mutex_unlock(&xra->lock); + + return ret; +} + +static int xra1403_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + return xra1403_set_bit(gpiochip_get_data(chip), XRA_GCR, offset, 1); +} + +static int xra1403_direction_output(struct gpio_chip *chip, unsigned int offset, + int value) +{ + int ret; + struct xra1403 *xra = gpiochip_get_data(chip); + + ret = xra1403_set_bit(xra, XRA_OCR, offset, value); + if (ret) + return ret; + + ret = xra1403_set_bit(xra, XRA_GCR, offset, 0); + + return ret; +} + +static int xra1403_get(struct gpio_chip *chip, unsigned int offset) +{ + return xra1403_get_bit(gpiochip_get_data(chip), XRA_GSR, offset); +} + +static void xra1403_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + xra1403_set_bit(gpiochip_get_data(chip), XRA_OCR, offset, value); +} + +#ifdef CONFIG_DEBUG_FS +#define XRA_REGS 0x16 +static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + int reg; + struct xra1403 *xra = gpiochip_get_data(chip); + int value[XRA_REGS]; + int i; + unsigned int gcr; + unsigned int gsr; + + seq_puts(s, "xra reg:"); + for (reg = 0; reg < XRA_REGS; reg++) + seq_printf(s, " %2.2x", reg); + seq_puts(s, "\n value:"); + for (reg = 0; reg < XRA_REGS; reg++) { + value[reg] = xra1403_get_byte(xra, reg); + seq_printf(s, " %2.2x", value[reg]); + } + seq_puts(s, "\n"); + + gcr = value[XRA_GCR + 1] << 8 | value[XRA_GCR]; + gsr = value[XRA_GSR + 1] << 8 | value[XRA_GSR]; + for (i = 0; i < chip->ngpio; i++) { + const char *label = gpiochip_is_requested(chip, i); + + if (!label) + continue; + + seq_printf(s, " gpio-%-3d (%-12s) %s %s\n", + chip->base + i, label, + (gcr & BIT(i)) ? "in" : "out", + (gsr & BIT(i)) ? "hi" : "lo"); + } +} +#else +#define xra1403_dbg_show NULL +#endif + +static int xra1403_probe(struct spi_device *spi) +{ + struct xra1403 *xra; + struct gpio_desc *reset_gpio; + + xra = devm_kzalloc(&spi->dev, sizeof(*xra), GFP_KERNEL); + if (!xra) + return -ENOMEM; + + /* bring the chip out of reset */ + reset_gpio = gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) + dev_warn(&spi->dev, "could not get reset-gpios\n"); + else if (reset_gpio) + gpiod_put(reset_gpio); + + mutex_init(&xra->lock); + + xra->chip.direction_input = xra1403_direction_input; + xra->chip.direction_output = xra1403_direction_output; + xra->chip.get = xra1403_get; + xra->chip.set = xra1403_set; + xra->chip.dbg_show = xra1403_dbg_show; + + xra->chip.ngpio = 16; + xra->chip.label = "xra1403"; + + xra->chip.base = -1; + xra->chip.can_sleep = true; + xra->chip.parent = &spi->dev; + xra->chip.owner = THIS_MODULE; + + xra->spi = spi; + spi_set_drvdata(spi, xra); + + return gpiochip_add_data(&xra->chip, xra); +} + +static int xra1403_remove(struct spi_device *spi) +{ + struct xra1403 *xra = spi_get_drvdata(spi); + + gpiochip_remove(&xra->chip); + + return 0; +} + +static const struct spi_device_id xra1403_ids[] = { + { "xra1403" }, + {}, +}; +MODULE_DEVICE_TABLE(spi, xra1403_ids); + +static const struct of_device_id xra1403_spi_of_match[] = { + { .compatible = "exar,xra1403" }, + {}, +}; +MODULE_DEVICE_TABLE(of, xra1403_spi_of_match); + +static struct spi_driver xra1403_driver = { + .probe = xra1403_probe, + .remove = xra1403_remove, + .id_table = xra1403_ids, + .driver = { + .name = "xra1403", + .of_match_table = of_match_ptr(xra1403_spi_of_match), + }, +}; + +static int __init xra1403_init(void) +{ + return spi_register_driver(&xra1403_driver); +} + +/* + * register after spi postcore initcall and before + * subsys initcalls that may rely on these GPIOs + */ +subsys_initcall(xra1403_init); + +static void __exit xra1403_exit(void) +{ + spi_unregister_driver(&xra1403_driver); +} +module_exit(xra1403_exit); + +MODULE_AUTHOR("Nandor Han <nandor.han@ge.com>"); +MODULE_AUTHOR("Semi Malinen <semi.malinen@ge.com>"); +MODULE_DESCRIPTION("GPIO expander driver for EXAR XRA1403"); +MODULE_LICENSE("GPL v2");