From owner-svn-src-stable@freebsd.org Mon Sep 11 17:01:28 2017 Return-Path: Delivered-To: svn-src-stable@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 68CAFE168F4; Mon, 11 Sep 2017 17:01:28 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 42B2E68862; Mon, 11 Sep 2017 17:01:28 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v8BH1Rdl030586; Mon, 11 Sep 2017 17:01:27 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v8BH1RKP030583; Mon, 11 Sep 2017 17:01:27 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201709111701.v8BH1RKP030583@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore Date: Mon, 11 Sep 2017 17:01:27 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r323446 - stable/11/sys/dev/iicbus X-SVN-Group: stable-11 X-SVN-Commit-Author: ian X-SVN-Commit-Paths: stable/11/sys/dev/iicbus X-SVN-Commit-Revision: 323446 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Sep 2017 17:01:28 -0000 Author: ian Date: Mon Sep 11 17:01:26 2017 New Revision: 323446 URL: https://svnweb.freebsd.org/changeset/base/323446 Log: MFC r321583, r321584: Add a pair of convenience routines for doing simple "register" read/writes on i2c devices, where the "register" can be any length. Add support for tracking nested calls to iicbus_request/release_bus(). Usually it is sufficient to use iicbus_transfer_excl(), or one of the higher-level convenience functions that use it, to reserve the bus for the duration of each register access. Occasionally it is important that a series of accesses or read-modify-write operations must be done without any other intervening access to the device, to prevent corrupting state. Modified: stable/11/sys/dev/iicbus/iicbus.h stable/11/sys/dev/iicbus/iiconf.c stable/11/sys/dev/iicbus/iiconf.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/dev/iicbus/iicbus.h ============================================================================== --- stable/11/sys/dev/iicbus/iicbus.h Mon Sep 11 15:59:20 2017 (r323445) +++ stable/11/sys/dev/iicbus/iicbus.h Mon Sep 11 17:01:26 2017 (r323446) @@ -39,6 +39,7 @@ struct iicbus_softc { device_t dev; /* Myself */ device_t owner; /* iicbus owner device structure */ + u_int owncount; /* iicbus ownership nesting count */ u_char started; /* address of the 'started' slave * 0 if no start condition succeeded */ u_char strict; /* deny operations that violate the Modified: stable/11/sys/dev/iicbus/iiconf.c ============================================================================== --- stable/11/sys/dev/iicbus/iiconf.c Mon Sep 11 15:59:20 2017 (r323445) +++ stable/11/sys/dev/iicbus/iiconf.c Mon Sep 11 17:01:26 2017 (r323446) @@ -113,26 +113,30 @@ iicbus_request_bus(device_t bus, device_t dev, int how IICBUS_LOCK(sc); - while ((error == 0) && (sc->owner != NULL)) + while (error == 0 && sc->owner != NULL && sc->owner != dev) error = iicbus_poll(sc, how); if (error == 0) { - sc->owner = dev; - /* - * Drop the lock around the call to the bus driver. - * This call should be allowed to sleep in the IIC_WAIT case. - * Drivers might also need to grab locks that would cause LOR - * if our lock is held. - */ - IICBUS_UNLOCK(sc); - /* Ask the underlying layers if the request is ok */ - error = IICBUS_CALLBACK(device_get_parent(bus), - IIC_REQUEST_BUS, (caddr_t)&how); - IICBUS_LOCK(sc); - - if (error != 0) { - sc->owner = NULL; - wakeup_one(sc); + ++sc->owncount; + if (sc->owner == NULL) { + sc->owner = dev; + /* + * Drop the lock around the call to the bus driver, it + * should be allowed to sleep in the IIC_WAIT case. + * Drivers might also need to grab locks that would + * cause a LOR if our lock is held. + */ + IICBUS_UNLOCK(sc); + /* Ask the underlying layers if the request is ok */ + error = IICBUS_CALLBACK(device_get_parent(bus), + IIC_REQUEST_BUS, (caddr_t)&how); + IICBUS_LOCK(sc); + + if (error != 0) { + sc->owner = NULL; + sc->owncount = 0; + wakeup_one(sc); + } } } @@ -150,7 +154,6 @@ int iicbus_release_bus(device_t bus, device_t dev) { struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus); - int error; IICBUS_LOCK(sc); @@ -159,26 +162,16 @@ iicbus_release_bus(device_t bus, device_t dev) return (IIC_EBUSBSY); } - /* - * Drop the lock around the call to the bus driver. - * This call should be allowed to sleep in the IIC_WAIT case. - * Drivers might also need to grab locks that would cause LOR - * if our lock is held. - */ - IICBUS_UNLOCK(sc); - /* Ask the underlying layers if the release is ok */ - error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL); - - if (error == 0) { + if (--sc->owncount == 0) { + /* Drop the lock while informing the low-level driver. */ + IICBUS_UNLOCK(sc); + IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL); IICBUS_LOCK(sc); sc->owner = NULL; - - /* wakeup a waiting thread */ wakeup_one(sc); - IICBUS_UNLOCK(sc); } - - return (error); + IICBUS_UNLOCK(sc); + return (0); } /* @@ -469,4 +462,56 @@ iicbus_transfer_gen(device_t dev, struct iic_msg *msgs if (error != 0 && started) iicbus_stop(bus); return (error); +} + +int +iicdev_readfrom(device_t slavedev, uint8_t regaddr, void *buffer, + uint16_t buflen, int waithow) +{ + struct iic_msg msgs[2]; + uint8_t slaveaddr; + + /* + * Two transfers back to back with a repeat-start between them; first we + * write the address-within-device, then we read from the device. + */ + slaveaddr = iicbus_get_addr(slavedev); + + msgs[0].slave = slaveaddr; + msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP; + msgs[0].len = 1; + msgs[0].buf = ®addr; + + msgs[1].slave = slaveaddr; + msgs[1].flags = IIC_M_RD; + msgs[1].len = buflen; + msgs[1].buf = buffer; + + return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow)); +} + +int iicdev_writeto(device_t slavedev, uint8_t regaddr, void *buffer, + uint16_t buflen, int waithow) +{ + struct iic_msg msgs[2]; + uint8_t slaveaddr; + + /* + * Two transfers back to back with no stop or start between them; first + * we write the address then we write the data to that address, all in a + * single transfer from two scattered buffers. + */ + slaveaddr = iicbus_get_addr(slavedev); + + msgs[0].slave = slaveaddr; + msgs[0].flags = IIC_M_WR | IIC_M_NOSTOP; + msgs[0].len = 1; + msgs[0].buf = ®addr; + + msgs[1].slave = slaveaddr; + msgs[1].flags = IIC_M_WR | IIC_M_NOSTART; + msgs[1].len = buflen; + msgs[1].buf = buffer; + + return (iicbus_transfer_excl(slavedev, msgs, nitems(msgs), waithow)); } Modified: stable/11/sys/dev/iicbus/iiconf.h ============================================================================== --- stable/11/sys/dev/iicbus/iiconf.h Mon Sep 11 15:59:20 2017 (r323445) +++ stable/11/sys/dev/iicbus/iiconf.h Mon Sep 11 17:01:26 2017 (r323446) @@ -133,6 +133,16 @@ int iicbus_transfer_excl(device_t bus, struct iic_msg int how); int iicbus_transfer_gen(device_t bus, struct iic_msg *msgs, uint32_t nmsgs); +/* + * Simple register read/write routines, but the "register" can be any size. + * The transfers are done with iicbus_transfer_excl(). Reads use a repeat-start + * between sending the address and reading; writes use a single start/stop. + */ +int iicdev_readfrom(device_t _slavedev, uint8_t _regaddr, void *_buffer, + uint16_t _buflen, int _waithow); +int iicdev_writeto(device_t _slavedev, uint8_t _regaddr, void *_buffer, + uint16_t _buflen, int _waithow); + #define IICBUS_MODVER 1 #define IICBUS_MINVER 1 #define IICBUS_MAXVER 1