Code quality in the Linux kernel varies a lot per individual driver or subsystem. Many interfaces are under-documented: you have to read the implementation code and make an educated guess at what the intended interface was. And a lot of the error handling paths contain bugs, since those are rarely exercised when testing manually.
The Linux kernel might seem elegant if you just read the code superficially. Once you start making changes and have to know exactly how it works, you'll see the problems that many parts of the kernel code have. While there is certainly a lot worse code out there, I wouldn't use the kernel as a shining example of elegant code.
There is one thing I learned from the Linux coding style though: avoiding typedefs and just writing "struct blah" in full helps make code accessible to new readers: the less indirections, the sooner you find what you're looking for. The same thing holds for avoiding typedef aliases for integer types and using macros sparingly.