diff --git a/package/base-files/files/lib/functions/eeprom.sh b/package/base-files/files/lib/functions/eeprom.sh
new file mode 100644
index 0000000000..80df3bb359
--- /dev/null
+++ b/package/base-files/files/lib/functions/eeprom.sh
@@ -0,0 +1,88 @@
+. /lib/functions.sh
+. /lib/functions/system.sh
+
+eeprom_die() {
+	echo "eeprom: " "$*"
+	exit 1
+}
+
+ath10kcal_die() {
+	echo "ath10cal: " "$*"
+	exit 1
+}
+
+mtd_eeprom_extract() {
+	local part=$1
+	local offset=$2
+	local count=$3
+	local mtd
+
+	mtd=$(find_mtd_chardev $part)
+	[ -n "$mtd" ] || \
+		eeprom_die "no mtd device found for partition $part"
+
+	dd if=$mtd of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
+		eeprom_die "failed to extract from $mtd"
+}
+
+mtd_eeprom_extract_check() {
+	local part=$1
+	local offset=$2
+	local count=$3
+	local mtd cal_size
+
+	mtd=$(find_mtd_chardev $part)
+	[ -n "$mtd" ] || \
+		eeprom_die "no mtd device found for partition $part"
+
+	# Check that the calibration data size in header equals the desired size
+	cal_size=$(dd if=$mtd bs=2 count=1 skip=$(( $offset / 2 )) conv=swab 2>/dev/null | hexdump -ve '1/2 "%d"')
+
+	[ "$count" = "$cal_size" ] || \
+		eeprom_die "no calibration data found in $part"
+
+	dd if=$mtd of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
+		eeprom_die "failed to extract from $mtd"
+}
+
+mtd_eeprom_extract_reverse() {
+	local part=$1
+	local offset=$2
+	local count=$3
+	local mtd
+	local reversed
+	local caldata
+
+	mtd=$(find_mtd_chardev "$part")
+	reversed=$(hexdump -v -s $offset -n $count -e '/1 "%02x "' $mtd)
+
+	for byte in $reversed; do
+		caldata="\x${byte}${caldata}"
+	done
+
+	printf "%b" "$caldata" > /lib/firmware/$FIRMWARE
+}
+
+ubi_eeprom_extract() {
+	local part=$1
+	local offset=$2
+	local count=$3
+	local ubidev=$(nand_find_ubi $CI_UBIPART)
+	local ubi
+
+	ubi=$(nand_find_volume $ubidev $part)
+	[ -n "$ubi" ] || \
+		eeprom_die "no UBI volume found for $part"
+
+	dd if=/dev/$ubi of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
+		eeprom_die "failed to extract from $ubi"
+}
+
+ath10kcal_from_file() {
+	local source=$1
+	local offset=$2
+	local count=$3
+
+	dd if=$source of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
+		ath10kcal_die "failed to extract calibration data from $source"
+}
diff --git a/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom b/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
index 208d5f6bff..6b94b19ee7 100644
--- a/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
+++ b/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
@@ -2,60 +2,7 @@
 
 [ -e /lib/firmware/$FIRMWARE ] && exit 0
 
-. /lib/functions.sh
-. /lib/functions/system.sh
-
-ath9k_eeprom_die() {
-	echo "ath9k eeprom: " "$*"
-	exit 1
-}
-
-ath9k_eeprom_extract() {
-	local part=$1
-	local offset=$2
-	local count=$3
-	local mtd
-
-	mtd=$(find_mtd_chardev $part)
-	[ -n "$mtd" ] || \
-		ath9k_eeprom_die "no mtd device found for partition $part"
-
-	dd if=$mtd of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
-		ath9k_eeprom_die "failed to extract from $mtd"
-}
-
-ath9k_ubi_eeprom_extract() {
-	local part=$1
-	local offset=$2
-	local count=$3
-	local ubidev=$(nand_find_ubi $CI_UBIPART)
-	local ubi
-
-	ubi=$(nand_find_volume $ubidev $part)
-	[ -n "$ubi" ] || \
-		ath9k_eeprom_die "no UBI volume found for $part"
-
-	dd if=/dev/$ubi of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
-		ath9k_eeprom_die "failed to extract from $ubi"
-}
-
-ath9k_eeprom_extract_reverse() {
-	local part=$1
-	local offset=$2
-	local count=$3
-	local mtd
-	local reversed
-	local caldata
-
-	mtd=$(find_mtd_chardev "$part")
-	reversed=$(hexdump -v -s $offset -n $count -e '/1 "%02x "' $mtd)
-
-	for byte in $reversed; do
-		caldata="\x${byte}${caldata}"
-	done
-
-	printf "%b" "$caldata" > /lib/firmware/$FIRMWARE
-}
+. /lib/functions/eeprom.sh
 
 ath9k_patch_firmware_mac() {
 	local mac=$1
@@ -72,48 +19,48 @@ case "$FIRMWARE" in
 	case $board in
 	c-55|\
 	c-60)
-		ath9k_eeprom_extract "art" 4096 2048
+		mtd_eeprom_extract "art" 4096 2048
 		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary art 0) +1)
 		;;
 	fritz4020|\
 	fritz450e)
-		ath9k_eeprom_extract_reverse "urlader" 5441 1088
+		mtd_eeprom_extract_reverse "urlader" 5441 1088
 		;;
 	mr18)
 		. /lib/upgrade/nand.sh
 
 		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
-			ath9k_ubi_eeprom_extract "caldata" 4096 2048
+			ubi_eeprom_extract "caldata" 4096 2048
 		else
-			ath9k_eeprom_extract "odm-caldata" 4096 2048
+			mtd_eeprom_extract "odm-caldata" 4096 2048
 		fi
 		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +1)
 		;;
 	r6100 | \
 	wndr3700v4 | \
 	wndr4300)
-		ath9k_eeprom_extract "caldata" 4096 2048
+		mtd_eeprom_extract "caldata" 4096 2048
 		ath9k_patch_firmware_mac $(mtd_get_mac_binary caldata 0)
 		;;
 	rambutan)
-		ath9k_eeprom_extract "art" 4096 2048
+		mtd_eeprom_extract "art" 4096 2048
 		;;
 	wlr8100)
-		ath9k_eeprom_extract "art" 4096 2048
+		mtd_eeprom_extract "art" 4096 2048
 		ath9k_patch_firmware_mac $(mtd_get_mac_ascii u-boot-env "ethaddr")
 		;;
 	z1)
 		. /lib/upgrade/nand.sh
 
 		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
-			ath9k_ubi_eeprom_extract "caldata" 4096 2048
+			ubi_eeprom_extract "caldata" 4096 2048
 		else
-			ath9k_eeprom_extract "origcaldata" 4096 2048
+			mtd_eeprom_extract "origcaldata" 4096 2048
 		fi
 		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +2)
 		;;
 	*)
-		ath9k_eeprom_die "board $board is not supported yet"
+		eeprom_die "board $board is not supported yet"
 		;;
 	esac
 	;;
@@ -121,39 +68,39 @@ case "$FIRMWARE" in
 "pci_wmac0.eeprom")
 	case $board in
 	c-55)
-		ath9k_eeprom_extract "art" 20480 2048
+		mtd_eeprom_extract "art" 20480 2048
 		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary art 0) +2)
 		;;
 	fritz300e)
-		ath9k_eeprom_extract_reverse "urloader" 5441 1088
+		mtd_eeprom_extract_reverse "urloader" 5441 1088
 		;;
 	mr18)
 		. /lib/upgrade/nand.sh
 
 		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
-			ath9k_ubi_eeprom_extract "caldata" 20480 2048
+			ubi_eeprom_extract "caldata" 20480 2048
 		else
-			ath9k_eeprom_extract "odm-caldata" 20480 2048
+			mtd_eeprom_extract "odm-caldata" 20480 2048
 		fi
 		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +2)
 		;;
 	wndr3700v4 | \
 	wndr4300)
-		ath9k_eeprom_extract "caldata" 20480 2048
+		mtd_eeprom_extract "caldata" 20480 2048
 		ath9k_patch_firmware_mac $(mtd_get_mac_binary caldata 12)
 		;;
 	z1)
 		. /lib/upgrade/nand.sh
 
 		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
-			ath9k_ubi_eeprom_extract "caldata" 86016 4096
+			ubi_eeprom_extract "caldata" 86016 4096
 		else
-			ath9k_eeprom_extract "origcaldata" 86016 4096
+			mtd_eeprom_extract "origcaldata" 86016 4096
 		fi
 		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +3)
 		;;
 	*)
-		ath9k_eeprom_die "board $board is not supported yet"
+		eeprom_die "board $board is not supported yet"
 		;;
 	esac
 	;;
@@ -164,14 +111,14 @@ case "$FIRMWARE" in
 		. /lib/upgrade/nand.sh
 
 		if [ -n "$(nand_find_volume ubi0 caldata)" ]; then
-			ath9k_ubi_eeprom_extract "caldata" 36864 2048
+			ubi_eeprom_extract "caldata" 36864 2048
 		else
-			ath9k_eeprom_extract "odm-caldata" 36864 2048
+			mtd_eeprom_extract "odm-caldata" 36864 2048
 		fi
 		ath9k_patch_firmware_mac $(macaddr_add $(mtd_get_mac_binary_ubi board-config 102) +3)
 		;;
 	*)
-		ath9k_eeprom_die "board $board is not supported yet"
+		eeprom_die "board $board is not supported yet"
 		;;
 	esac
 	;;
diff --git a/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
index cd5c1c2bcb..37223686fb 100644
--- a/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
+++ b/target/linux/ar71xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
@@ -1,38 +1,6 @@
 #!/bin/sh
 
-ath10kcal_die() {
-	echo "ath10cal: " "$*"
-	exit 1
-}
-
-ath10kcal_from_file() {
-	local source=$1
-	local offset=$2
-	local count=$3
-
-	dd if=$source of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
-		ath10kcal_die "failed to extract calibration data from $source"
-}
-
-ath10kcal_extract() {
-	local part=$1
-	local offset=$2
-	local count=$3
-	local mtd cal_size
-
-	mtd=$(find_mtd_chardev $part)
-	[ -n "$mtd" ] || \
-		ath10kcal_die "no mtd device found for partition $part"
-
-	# Check that the calibration data size in header equals the desired size
-	cal_size=$(dd if=$mtd bs=2 count=1 skip=$(( $offset / 2 )) conv=swab 2>/dev/null | hexdump -ve '1/2 "%d"')
-
-	[ "$count" = "$cal_size" ] || \
-		ath10kcal_die "no calibration data found in $part"
-
-	dd if=$mtd of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
-		ath10kcal_die "failed to extract calibration data from $mtd"
-}
+. /lib/functions/eeprom.sh
 
 ath10kcal_patch_mac() {
 	local mac=$1
@@ -57,17 +25,17 @@ case "$FIRMWARE" in
 	mr1750|\
 	mr1750v2|\
 	om5p-acv2)
-		ath10kcal_extract "ART" 20480 2116
+		mtd_eeprom_extract_check "ART" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) +16)
 		;;
 	archer-c25-v1|\
 	tl-wdr6500-v2)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth1/address) -2)
 		;;
 	archer-c7-v4|\
 	archer-c7-v5)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) -1)
 		;;
 	cf-e355ac-v1|\
@@ -81,42 +49,42 @@ case "$FIRMWARE" in
 	oolite-v5.2-dev|\
 	sr3200|\
 	xd3200)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		;;
 	dap-2695-a1)
-		ath10kcal_extract "radiocfg" 20480 2116
+		mtd_eeprom_extract_check "radiocfg" 20480 2116
 		ath10kcal_patch_mac $(mtd_get_mac_ascii bdcfg wlanmac_a)
 		;;
 	dir-869-a1|\
 	qihoo-c301)
-		ath10kcal_extract "radiocfg" 20480 2116
+		mtd_eeprom_extract_check "radiocfg" 20480 2116
 		ath10kcal_patch_mac $(mtd_get_mac_ascii devdata wlan5mac)
 		;;
 	dw33d)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		ath10kcal_patch_mac $(mtd_get_mac_binary art 18)
 		;;
 	epg5000|\
 	esr1750)
-		ath10kcal_extract "caldata" 20480 2116
+		mtd_eeprom_extract_check "caldata" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) +1)
 		;;
 	gl-ar750s|\
 	gl-ar750|\
 	tl-wpa8630)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) +1)
 		;;
 	koala)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(mtd_get_mac_binary art 12) +0)
 		;;
 	mc-mac1200r)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth1/address) -1)
 		;;
 	r6100)
-		ath10kcal_extract "caldata" 20480 2116
+		mtd_eeprom_extract_check "caldata" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth1/address) +2)
 		;;
 	rb-952ui-5ac2nd|\
@@ -126,15 +94,15 @@ case "$FIRMWARE" in
 	re355|\
 	re450|\
 	tl-wr902ac-v1)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) -2)
 		;;
 	unifiac-lite|\
 	unifiac-pro)
-		ath10kcal_extract "EEPROM" 20480 2116
+		mtd_eeprom_extract_check "EEPROM" 20480 2116
 		;;
 	wi2a-ac200i)
-		ath10kcal_extract "ART" 20480 2116
+		mtd_eeprom_extract_check "ART" 20480 2116
 		;;
 	esac
 	;;
@@ -142,16 +110,16 @@ case "$FIRMWARE" in
 	case $board in
 	archer-c5|\
 	archer-c7)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth1/address) -2)
 		;;
 	nbg6616|\
 	nbg6716)
-		ath10kcal_extract "RFdata" 20480 2116
+		mtd_eeprom_extract_check "RFdata" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth1/address) -2)
 		;;
 	om5p-ac)
-		ath10kcal_extract "ART" 20480 2116
+		mtd_eeprom_extract_check "ART" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) +16)
 		;;
 	rb-911g-5hpacd|\
@@ -160,7 +128,7 @@ case "$FIRMWARE" in
 		ath10kcal_from_file "/sys/firmware/routerboot/ext_wlan_data" 20480 2116
 		;;
 	wlr8100)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract_check "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(mtd_get_mac_ascii u-boot-env ethaddr) +1)
 		;;
 	esac
@@ -173,18 +141,18 @@ case "$FIRMWARE" in
 	archer-c60-v1|\
 	cf-e355ac-v2|\
 	cf-e375ac)
-		ath10kcal_extract "art" 20480 12064
+		mtd_eeprom_extract_check "art" 20480 12064
 		ln -sf /lib/firmware/ath10k/pre-cal-pci-0000\:00\:00.0.bin \
 			/lib/firmware/ath10k/QCA9888/hw2.0/board.bin
 		;;
 	archer-c60-v2)
-		ath10kcal_extract "art" 20480 12064
+		mtd_eeprom_extract_check "art" 20480 12064
 		ln -sf /lib/firmware/ath10k/pre-cal-pci-0000\:00\:00.0.bin \
 			/lib/firmware/ath10k/QCA9888/hw2.0/board.bin
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) -1)
 		;;
 	cf-e385ac)
-		ath10kcal_extract "art" 20480 12064
+		mtd_eeprom_extract_check "art" 20480 12064
 		;;
 	esac
 	;;
diff --git a/target/linux/ath79/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom b/target/linux/ath79/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
index d8b292f4da..685bab4b05 100644
--- a/target/linux/ath79/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
+++ b/target/linux/ath79/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom
@@ -2,45 +2,7 @@
 
 [ -e /lib/firmware/$FIRMWARE ] && exit 0
 
-. /lib/functions.sh
-. /lib/functions/system.sh
-
-ath9k_eeprom_die() {
-	echo "ath9k eeprom: " "$*"
-	exit 1
-}
-
-ath9k_eeprom_extract() {
-	local part=$1
-	local offset=$2
-	local count=$3
-	local mtd
-
-	mtd=$(find_mtd_chardev $part)
-	[ -n "$mtd" ] || \
-		ath9k_eeprom_die "no mtd device found for partition $part"
-
-	dd if=$mtd of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
-		ath9k_eeprom_die "failed to extract from $mtd"
-}
-
-ath9k_eeprom_extract_reverse() {
-	local part=$1
-	local offset=$2
-	local count=$3
-	local mtd
-	local reversed
-	local caldata
-
-	mtd=$(find_mtd_chardev "$part")
-	reversed=$(hexdump -v -s $offset -n $count -e '/1 "%02x "' $mtd)
-
-	for byte in $reversed; do
-		caldata="\x${byte}${caldata}"
-	done
-
-	printf "%b" "$caldata" > /lib/firmware/$FIRMWARE
-}
+. /lib/functions/eeprom.sh
 
 xor() {
 	local val
@@ -98,50 +60,50 @@ case "$FIRMWARE" in
 "ath9k-eeprom-ahb-18100000.wmac.bin")
 	case $board in
 	avm,fritz4020)
-		ath9k_eeprom_extract_reverse "urlader" 5441 1088
+		mtd_eeprom_extract_reverse "urlader" 5441 1088
 		;;
 	dlink,dir-825-c1|\
 	dlink,dir-835-a1)
-		ath9k_eeprom_extract "art" 4096 1088
+		mtd_eeprom_extract "art" 4096 1088
 		ath9k_patch_fw_mac_crc $(mtd_get_mac_text "mac" 4) 2
 		;;
 	dlink,dir-859-a1)
-		ath9k_eeprom_extract "art" 4096 1088
+		mtd_eeprom_extract "art" 4096 1088
 		ath9k_patch_fw_mac $(mtd_get_mac_ascii devdata "wlan24mac") 2
 		;;
 	iodata,wn-ac1167dgr|\
 	iodata,wn-ac1600dgr|\
 	iodata,wn-ac1600dgr2|\
 	iodata,wn-ag300dgr)
-		ath9k_eeprom_extract "art" 4096 1088
+		mtd_eeprom_extract "art" 4096 1088
 		ath9k_patch_fw_mac $(mtd_get_mac_ascii u-boot-env ethaddr) 2
 		;;
 	nec,wg800hp)
-		ath9k_eeprom_extract "art" 4096 1088
+		mtd_eeprom_extract "art" 4096 1088
 		ath9k_patch_fw_mac $(mtd_get_mac_text board_data 1664) 2
 		;;
 	*)
-		ath9k_eeprom_die "board $board is not supported yet"
+		eeprom_die "board $board is not supported yet"
 		;;
 	esac
 	;;
 "ath9k-eeprom-pci-0000:00:00.0.bin")
 	case $board in
 	avm,fritz300e)
-		ath9k_eeprom_extract_reverse "urloader" 5441 1088
+		mtd_eeprom_extract_reverse "urloader" 5441 1088
 		;;
 	buffalo,whr-g301n|\
 	buffalo,wzr-hp-g302h-a1a0|\
 	tplink,tl-wr841-v5|\
 	tplink,tl-wr941-v4)
-		ath9k_eeprom_extract "art" 4096 3768
+		mtd_eeprom_extract "art" 4096 3768
 		;;
 	buffalo,wzr-hp-g450h)
-		ath9k_eeprom_extract "ART" 4096 1088
+		mtd_eeprom_extract "ART" 4096 1088
 		;;
 	dlink,dir-825-c1|\
 	dlink,dir-835-a1)
-		ath9k_eeprom_extract "art" 20480 1088
+		mtd_eeprom_extract "art" 20480 1088
 		ath9k_patch_fw_mac_crc $(macaddr_add $(mtd_get_mac_text "mac" 24) 1) 2
 		;;
 	ocedo,raccoon|\
@@ -149,7 +111,7 @@ case "$FIRMWARE" in
 	tplink,tl-wdr4300|\
 	tplink,tl-wdr4900-v2|\
 	winchannel,wb2000)
-		ath9k_eeprom_extract "art" 20480 1088
+		mtd_eeprom_extract "art" 20480 1088
 		;;
 	netgear,wnr612-v2|\
 	on,n150r|\
@@ -167,20 +129,20 @@ case "$FIRMWARE" in
 	ubnt,bullet-m|\
 	ubnt,nano-m|\
 	ubnt,rocket-m)
-		ath9k_eeprom_extract "art" 4096 4096
+		mtd_eeprom_extract "art" 4096 4096
 		;;
 	pqi,air-pen)
-		ath9k_eeprom_extract "art" 4096 2002
+		mtd_eeprom_extract "art" 4096 2002
 		;;
 	ubnt,unifi)
-		ath9k_eeprom_extract "art" 4096 2048
+		mtd_eeprom_extract "art" 4096 2048
 		;;
 	wd,mynet-wifi-rangeextender)
-		ath9k_eeprom_extract "art" 4096 4096
+		mtd_eeprom_extract "art" 4096 4096
 		ath9k_patch_fw_mac_crc $(nvram get wl0_hwaddr) "$mac" 2
 		;;
 	*)
-		ath9k_eeprom_die "board $board is not supported yet"
+		eeprom_die "board $board is not supported yet"
 		;;
 	esac
 	;;
@@ -190,14 +152,14 @@ case "$FIRMWARE" in
 	netgear,wndr3700|\
 	netgear,wndr3700v2|\
 	netgear,wndr3800)
-		ath9k_eeprom_extract "art" 4096 3768
+		mtd_eeprom_extract "art" 4096 3768
 		;;
 	dlink,dir-825-b1)
-		ath9k_eeprom_extract "caldata" 4096 3768
+		mtd_eeprom_extract "caldata" 4096 3768
 		ath9k_patch_fw_mac_crc $(mtd_get_mac_text "caldata" 65440) 524
 		;;
 	*)
-		ath9k_eeprom_die "board $board is not supported yet"
+		eeprom_die "board $board is not supported yet"
 		;;
 	esac
 	;;
@@ -207,14 +169,14 @@ case "$FIRMWARE" in
 	netgear,wndr3700|\
 	netgear,wndr3700v2|\
 	netgear,wndr3800)
-		ath9k_eeprom_extract "art" 20480 3768
+		mtd_eeprom_extract "art" 20480 3768
 		;;
 	dlink,dir-825-b1)
-		ath9k_eeprom_extract "caldata" 20480 3768
+		mtd_eeprom_extract "caldata" 20480 3768
 		ath9k_patch_fw_mac_crc $(macaddr_add $(mtd_get_mac_text "caldata" 65460) 1) 524
 		;;
 	*)
-		ath9k_eeprom_die "board $board is not supported yet"
+		eeprom_die "board $board is not supported yet"
 		;;
 	esac
 	;;
diff --git a/target/linux/ath79/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ath79/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
index f8e385be68..52f9582e10 100644
--- a/target/linux/ath79/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
+++ b/target/linux/ath79/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
@@ -1,6 +1,7 @@
 #!/bin/sh
 
 . /lib/functions/k2t.sh
+. /lib/functions/eeprom.sh
 
 # xor multiple hex values of the same length
 xor() {
@@ -18,34 +19,6 @@ xor() {
 	printf "%0${retlen}x" "$ret"
 }
 
-ath10kcal_die() {
-	echo "ath10cal: " "$*"
-	exit 1
-}
-
-ath10kcal_from_file() {
-	local source=$1
-	local offset=$2
-	local count=$3
-
-	dd if=$source of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
-		ath10kcal_die "failed to extract calibration data from $source"
-}
-
-ath10kcal_extract() {
-	local part=$1
-	local offset=$2
-	local count=$3
-	local mtd
-
-	mtd=$(find_mtd_chardev $part)
-	[ -n "$mtd" ] || \
-		ath10kcal_die "no mtd device found for partition $part"
-
-	dd if=$mtd of=/lib/firmware/$FIRMWARE iflag=skip_bytes bs=$count skip=$offset count=1 2>/dev/null || \
-		ath10kcal_die "failed to extract calibration data from $mtd"
-}
-
 ath10kcal_patch_mac() {
 	local mac=$1
 
@@ -79,9 +52,6 @@ ath10kcal_patch_mac_crc() {
 
 [ -e /lib/firmware/$FIRMWARE ] && exit 0
 
-. /lib/functions.sh
-. /lib/functions/system.sh
-
 board=$(board_name)
 
 case "$FIRMWARE" in
@@ -92,53 +62,53 @@ case "$FIRMWARE" in
 	devolo,dvl1750c|\
 	devolo,dvl1750e|\
 	devolo,dvl1750i)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract "art" 20480 2116
 		ath10kcal_patch_mac_crc $(macaddr_add $(mtd_get_mac_binary art 0) -1)
 		;;
 	dlink,dir-859-a1)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract "art" 20480 2116
 		ath10kcal_patch_mac $(mtd_get_mac_ascii devdata "wlan5mac")
 		;;
 	elecom,wrc-1750ghbk2-i)
-		ath10kcal_extract "ART" 20480 2116
+		mtd_eeprom_extract "ART" 20480 2116
 		;;
 	engenius,ews511ap|\
 	glinet,gl-ar750s|\
 	glinet,gl-x750|\
 	tplink,re450-v2)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) +1)
 		;;
 	iodata,wn-ac1167dgr|\
 	iodata,wn-ac1600dgr2)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(mtd_get_mac_ascii u-boot-env ethaddr) +1)
 		;;
 	nec,wg800hp)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract "art" 20480 2116
 		ath10kcal_patch_mac_crc $(mtd_get_mac_text board_data 2176)
 		;;
 	ocedo,koala)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract "art" 20480 2116
 		ath10kcal_patch_mac $(mtd_get_mac_binary art 12)
 		;;
 	openmesh,om5p-ac-v2)
-		ath10kcal_extract "ART" 20480 2116
+		mtd_eeprom_extract "ART" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) +16)
 		;;
 	tplink,archer-c2-v3)
-		ath10kcal_extract "ART" 20480 2116
+		mtd_eeprom_extract "ART" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) -1)
 		;;
 	tplink,archer-c5-v1|\
 	tplink,archer-c7-v2)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth1/address) -1)
 		;;
 	tplink,archer-a7-v5|\
 	tplink,archer-c7-v4|\
 	tplink,archer-c7-v5)
-		ath10kcal_extract "art" 20480 2116
+		mtd_eeprom_extract "art" 20480 2116
 		ath10kcal_patch_mac $(macaddr_add $(cat /sys/class/net/eth0/address) -1)
 		;;
 	ubnt,unifiac-lite|\
@@ -148,14 +118,14 @@ case "$FIRMWARE" in
 	ubnt,nanostation-ac|\
 	ubnt,nanostation-ac-loco|\
 	ubnt,unifiac-pro)
-		ath10kcal_extract "EEPROM" 20480 2116
+		mtd_eeprom_extract "EEPROM" 20480 2116
 		;;
 	esac
 	;;
 "ath10k/pre-cal-pci-0000:00:00.0.bin")
 	case $board in
 	phicomm,k2t)
-		ath10kcal_extract "art" 20480 12064
+		mtd_eeprom_extract "art" 20480 12064
 		ath10kcal_patch_mac_crc $(k2t_get_mac "5g_mac")
 		ln -sf /lib/firmware/ath10k/pre-cal-pci-0000\:00\:00.0.bin \
 			/lib/firmware/ath10k/QCA9888/hw2.0/board.bin
@@ -163,7 +133,7 @@ case "$FIRMWARE" in
 	tplink,archer-c58-v1|\
 	tplink,archer-c59-v1|\
 	tplink,archer-c6-v2)
-		ath10kcal_extract "art" 20480 12064
+		mtd_eeprom_extract "art" 20480 12064
 		ath10kcal_patch_mac_crc $(macaddr_add $(mtd_get_mac_binary mac 8) -1)
 		ln -sf /lib/firmware/ath10k/pre-cal-pci-0000\:00\:00.0.bin \
 			/lib/firmware/ath10k/QCA9888/hw2.0/board.bin
