Простейший способ "в лоб" - это char device, внутри которого 2 буфера, в один пишем, другой готов к чтению
из приложения через read(). При заполнении одного буфера DMA перезапускается на другой буфер. Либо "дмашить"
в кольцевой буфер. Как сделать лучше - см. спеки на железо.
Есть нюансы

Во-первых, вам нужно перезапустить DMA за 10мкс (по прерыванию, например). Не факт, что вы
успеете, т.к. если обращение к регистру занимает (к примеру) 1мкс, а вам нужно перезаписать 5шт - это уже 10мкс.
Некоторые DMA умны настолько, что могут сами брать дескрипторы из памяти и закольцовываться по их списку.
В этом случае перезапускать DMA нет необходимости. Если это не так и терять данные нельзя вообще - то вы
близки к теоретическому пределу железа - опять же, см. спеки на железо.
Во-вторых, при использовании своего char dev нужно убедиться, что никто через линуксовый SPI-фреймворк не
обращается к SPI контроллеру (и через DMA фреймворк тоже).
Что касается "сложности" драйверов в linux - это нормально

На самом деле там все довольно просто - почти
все разбито на слои и фреймворки для облегчения портируемости и расширения. Фактически, там используется ООП
подход, со всеми вытекающими. В итоге вход в это хозяйство усложняется (и кажется странным для людей
работавших до этого с МК осями/bare metal), но иначе никак. Вообще, такой подход характерен для всех
не-tiny мультиплатформенных ОС.
P.S. Есть фреймворк comedi, все еще стандарт де-факто для data acquisition. Но 100К семплов/с - немалая величина,
и с ней оверхед фреймворка может стать неприемлемым.