Kernel modules exist in kernel space and therefore by definition require system calls in order to be accessed from userspace, so yes with regard to them.
However, it is possible to create userspace drivers that are built on top of some kernel one, although in the end they must make system calls to operate. This is possible with, e.g., I2C devices; the userspace driver uses the kernel's SMBus API (which is all system calls). In that case some application might technically use some facility of the driver without passing through the system, but if the driver must actually interact with the hardware, then it's system calls again.
It's also possible to use
mmap() (a system call) on
/dev/mem, which is the system memory (see
man mem) and, since this includes the entirety of kernel space, exposes access to hardware. Manipulating this map then does not require any further system calls. I believe this is an unusual thing to do, partially because it sidesteps the kernel itself in a way that might be undesirable, and partially because making it portable from one architecture to another would involve redundancy1 -- so it is more likely to be used for hacking and experimentation than driver deployment in production systems.
Kernel drivers can expose a device node based interface to userland, which might be operable using
write() -- which are system calls.
1. If you write a normal kernel driver, or use a kernel userland API, the kernel itself covers portability issues; you can stick with one version of your code. If you use the memory mapping method, you'll have to have different versions of your code for every architecture (which the kernel already has, hence "redundant").