Just my opinion, but it seems like bad practice to force implementation of properties and methods that do not relate to the device that will be implementing the class. Doing so breaks the single responsibility principle.
All of that functionality should be broken up by purpose. So if IIODevice should be a base class that everything inherits from. Then there should be another layer, maybe a base ShiftRegister or IIOExpander class that defines the functionality that all ShiftRegisters/IOExpanders have in common. Then maybe an IOutputRegister, IInuputRegister, IIORegister, for the variations of the registers themselves, split by purpose.
IOutputRegister should not implement input register functionality, just as IInputRegister should not implement any IOutputRegister functionality. Then IIORegister would implement both sets of functionality, as its purpose is both input and output.
I could see using the current implementation if my goal was to chain Meadow boards together, but outside another micro controller, what other device will actually use all of the functionality implemented on the base IIODevice as currently written? I cant think of many. So at that point how re-usable is our interface? Not very, only 20-30% of the methods are going to be consumed on average. That's a lot of bloat to carry around and duplicate each time, if its not needed.
I may also not be seeing the whole picture here, so constructive feedback is appreciated.