diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 47ae3cebb61e..c7a4e567b623 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -298,7 +298,7 @@ snd-soc-max98504-objs := max98504.o
 snd-soc-simple-amplifier-objs := simple-amplifier.o
 snd-soc-tpa6130a2-objs := tpa6130a2.o
 snd-soc-tas2552-objs := tas2552.o
-snd-soc-tas2562-objs := tas2562.o
+snd-soc-tas2562-objs := tas2562.o tas25xx_dsp_loader.o
 
 obj-$(CONFIG_SND_SOC_88PM860X)	+= snd-soc-88pm860x.o
 obj-$(CONFIG_SND_SOC_AB8500_CODEC)	+= snd-soc-ab8500-codec.o
diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
index 7fae88655a0f..3e60fdec4cfd 100644
--- a/sound/soc/codecs/tas2562.c
+++ b/sound/soc/codecs/tas2562.c
@@ -7,6 +7,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/device.h>
+#include <linux/firmware.h>
 #include <linux/i2c.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
@@ -22,6 +23,7 @@
 #include <sound/tlv.h>
 
 #include "tas2562.h"
+#include "tas25xx_dsp_loader.h"
 
 #define TAS2562_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
 			 SNDRV_PCM_FORMAT_S32_LE)
@@ -44,22 +46,6 @@ static const unsigned int float_vol_db_lookup[] = {
 0x197a967f, 0x2013739e, 0x28619ae9, 0x32d64617, 0x40000000
 };
 
-struct tas2562_data {
-	struct snd_soc_component *component;
-	struct gpio_desc *sdz_gpio;
-	struct regmap *regmap;
-	struct device *dev;
-	struct i2c_client *client;
-	int v_sense_slot;
-	int i_sense_slot;
-	int volume_lvl;
-};
-
-enum tas256x_model {
-	TAS2562,
-	TAS2563,
-};
-
 static int tas2562_set_bias_level(struct snd_soc_component *component,
 				 enum snd_soc_bias_level level)
 {
@@ -343,6 +329,17 @@ static int tas2562_mute(struct snd_soc_dai *dai, int mute)
 					     mute ? TAS2562_MUTE : 0);
 }
 
+static void tas2562_fw_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_component *component = context;
+	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	ret = tas25xx_init_fw(tas2562, fw);
+	if (ret)
+		dev_err(tas2562->dev, "Firmware failed to initialize\n");
+}
+
 static int tas2562_codec_probe(struct snd_soc_component *component)
 {
 	struct tas2562_data *tas2562 = snd_soc_component_get_drvdata(component);
@@ -358,6 +355,12 @@ static int tas2562_codec_probe(struct snd_soc_component *component)
 	if (ret < 0)
 		return ret;
 
+	if (tas2562->load_firmware == 0 && tas2562->model_id == TAS2563)
+		request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+					tas2562->firmware_name, component->dev,
+					GFP_KERNEL, component,
+					tas2562_fw_loaded);
+
 	return 0;
 }
 
@@ -580,7 +583,7 @@ static struct snd_soc_dai_driver tas2562_dai[] = {
 static const struct regmap_range_cfg tas2562_ranges[] = {
 	{
 		.range_min = 0,
-		.range_max = 5 * 128,
+		.range_max = 255 * 128,
 		.selector_reg = TAS2562_PAGE_CTRL,
 		.selector_mask = 0xff,
 		.selector_shift = 0,
@@ -606,7 +609,7 @@ static const struct regmap_config tas2562_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
 
-	.max_register = 5 * 128,
+	.max_register = 255 * 128,
 	.cache_type = REGCACHE_RBTREE,
 	.reg_defaults = tas2562_reg_defaults,
 	.num_reg_defaults = ARRAY_SIZE(tas2562_reg_defaults),
@@ -634,6 +637,14 @@ static int tas2562_parse_dt(struct tas2562_data *tas2562)
 		dev_err(dev, "Looking up %s property failed %d\n",
 			"ti,imon-slot-no", ret);
 
+	if (tas2562->model_id != TAS2562) {
+		tas2562->load_firmware = fwnode_property_read_string(dev->fwnode,
+							"firmware-name",
+						       &tas2562->firmware_name);
+		if (tas2562->load_firmware)
+			dev_info(dev, "No firmware file to request\n");
+	}
+
 	return ret;
 }
 
@@ -650,6 +661,7 @@ static int tas2562_probe(struct i2c_client *client,
 
 	data->client = client;
 	data->dev = &client->dev;
+	data->model_id = id->driver_data;
 
 	tas2562_parse_dt(data);
 
diff --git a/sound/soc/codecs/tas2562.h b/sound/soc/codecs/tas2562.h
index 28e75fc431d0..66c15b05cd35 100644
--- a/sound/soc/codecs/tas2562.h
+++ b/sound/soc/codecs/tas2562.h
@@ -11,6 +11,7 @@
 #define __TAS2562_H__
 
 #define TAS2562_PAGE_CTRL	0x00
+#define TAS2562_BOOK_CTRL	0x7f
 
 #define TAS2562_REG(page, reg)	((page * 128) + reg)
 
@@ -40,6 +41,8 @@
 #define TAS2562_DVC_CFG3	TAS2562_REG(2, 0x0e)
 #define TAS2562_DVC_CFG4	TAS2562_REG(2, 0x0f)
 
+#define TAS25XX_DSP_MODE	TAS2562_REG(1, 2)
+
 #define TAS2562_RESET	BIT(0)
 
 #define TAS2562_MODE_MASK	GENMASK(1,0)
@@ -84,4 +87,26 @@
 #define TAS2562_TDM_CFG6_ISNS_EN	BIT(6)
 #define TAS2562_TDM_CFG6_ISNS_SLOT_MASK	GENMASK(5, 0)
 
+#define TAS2563_FW_HDR_OFFSET		134
+
+struct tas2562_data {
+	struct snd_soc_component *component;
+	struct gpio_desc *sdz_gpio;
+	struct regmap *regmap;
+	struct device *dev;
+	struct i2c_client *client;
+	struct tas25xx_fw_data *fw_data;
+	const char *firmware_name;
+	int load_firmware;
+	int model_id;
+	int v_sense_slot;
+	int i_sense_slot;
+	int volume_lvl;
+};
+
+enum tas2562_id {
+	TAS2562,
+	TAS2563,
+};
+
 #endif /* __TAS2562_H__ */
diff --git a/sound/soc/codecs/tas25xx_dsp_loader.c b/sound/soc/codecs/tas25xx_dsp_loader.c
new file mode 100644
index 000000000000..45cc5a253898
--- /dev/null
+++ b/sound/soc/codecs/tas25xx_dsp_loader.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Firmware loader for the Texas Instruments TAS25XX DSP
+// Copyright (C) 2020 Texas Instruments Inc.
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "tas25xx_dsp_loader.h"
+
+static void tas25xx_process_fw_delay(struct tas2562_data *tas2562, u8 *fw_out)
+{
+	u16 fw_delay = fw_out[2] << 8 | fw_out[3];
+
+	mdelay(fw_delay);
+}
+
+static int tas25xx_process_fw_single(struct tas2562_data *tas2562,
+				     struct tas25xx_cmd_data *cmd_data,
+				     u8 *fw_out)
+{
+	int num_writes = cpu_to_be16(cmd_data->length);
+	int i;
+	int ret;
+	int offset = 4;
+	int reg_data, write_reg;
+
+	for (i = 0; i < num_writes; i++) {
+		/* Reset Page to 0 */
+		ret = regmap_write(tas2562->regmap, TAS2562_PAGE_CTRL, 0);
+		if (ret)
+			return ret;
+
+		cmd_data->book = fw_out[offset];
+		cmd_data->page = fw_out[offset + 1];
+		cmd_data->offset = fw_out[offset + 2];
+		reg_data = fw_out[offset + 3];
+		offset += 4;
+
+		ret = regmap_write(tas2562->regmap, TAS2562_BOOK_CTRL,
+				   cmd_data->book);
+		if (ret)
+			return ret;
+
+		write_reg = TAS2562_REG(cmd_data->page, cmd_data->offset);
+		ret = regmap_write(tas2562->regmap, write_reg, reg_data);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int tas25xx_process_fw_burst(struct tas2562_data *tas2562,
+				    struct tas25xx_cmd_data *cmd_data,
+				    u8 *fw_out, int size)
+{
+	int hdr_size = sizeof(struct tas25xx_cmd_data);
+	u8 *data = &fw_out[hdr_size];
+	int ret;
+	int reg_data = TAS2562_REG(cmd_data->page, cmd_data->offset);
+
+	/* Reset Page to 0 */
+	ret = regmap_write(tas2562->regmap, TAS2562_PAGE_CTRL, 0);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(tas2562->regmap, TAS2562_BOOK_CTRL, cmd_data->book);
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_write(tas2562->regmap, reg_data, data,
+				cpu_to_be16(cmd_data->length));
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int tas25xx_process_block(struct tas2562_data *tas2562, u8 *data)
+{
+	struct tas25xx_cmd_data *cmd_data = (struct tas25xx_cmd_data *)data;
+	int ret;
+	int total_written;
+	int hdr_size = sizeof(struct tas25xx_cmd_data);
+
+	switch (cpu_to_be16(cmd_data->cmd_type)) {
+	case TAS25XX_CMD_SING_W:
+		ret = tas25xx_process_fw_single(tas2562, cmd_data, data);
+		if (ret) {
+			dev_err(tas2562->dev,
+				"Failed to process single write %d\n", ret);
+			return ret;
+		}
+
+		hdr_size -= 4;
+		total_written = cpu_to_be16(cmd_data->length) * 4 + hdr_size;
+		break;
+	case TAS25XX_CMD_BURST:
+		ret = tas25xx_process_fw_burst(tas2562, cmd_data, data,
+					       cpu_to_be16(cmd_data->length));
+		if (ret) {
+			dev_err(tas2562->dev,
+				"Failed to process burst write %d\n", ret);
+			return ret;
+		}
+		total_written = cpu_to_be16(cmd_data->length) + hdr_size;
+		break;
+	case TAS25XX_CMD_DELAY:
+		tas25xx_process_fw_delay(tas2562, data);
+		total_written = 4;
+		break;
+	default:
+		total_written = 0;
+		break;
+	};
+
+	return total_written;
+}
+
+
+static int tas25xx_write_program(struct tas2562_data *tas2562, int prog_num)
+{
+	struct tas25xx_fw_hdr *fw_hdr = tas2562->fw_data->fw_hdr;
+	struct tas25xx_program_info *prog_info;
+	int offset = sizeof(struct tas25xx_program_info);
+	int prog_offset = 0;
+	int i;
+	int length = 0;
+
+	if (prog_num > fw_hdr->num_programs)
+		return -EINVAL;
+
+	if (prog_num) {
+		for (i = 0; i < prog_num; i++)
+			prog_offset += cpu_to_be32(fw_hdr->prog_size[i]);
+	}
+
+	offset += prog_offset;
+	prog_info = (struct tas25xx_program_info *)&tas2562->fw_data->prog_info[prog_offset];
+
+	for (i = 0; i < cpu_to_be32(prog_info->blk_data.num_subblocks); i++) {
+		length = tas25xx_process_block(tas2562,
+					  &tas2562->fw_data->prog_info[offset]);
+		if (length < 0)
+			return length;
+
+		offset += length;
+	}
+
+	/* Reset Book to 0 */
+	regmap_write(tas2562->regmap, TAS2562_BOOK_CTRL, 0);
+
+	return 0;
+}
+
+static int tas25xx_write_config(struct tas2562_data *tas2562, int config_num)
+{
+	struct tas25xx_fw_hdr *fw_hdr = tas2562->fw_data->fw_hdr;
+	struct tas25xx_config_info *cfg_info;
+	int config_offset = 0;
+	int i;
+	int offset = sizeof(struct tas25xx_config_info);
+	int length = 0;
+
+	if (config_num > fw_hdr->num_configs)
+		return -EINVAL;
+
+	if (config_num)
+		for (i = 0; i < config_num; i++)
+			config_offset += cpu_to_be32(fw_hdr->config_size[i]);
+
+	cfg_info = (struct tas25xx_config_info *)&tas2562->fw_data->config_info[config_offset];
+	offset += config_offset;
+
+	for (i = 0; i < cpu_to_be32(cfg_info->blk_data.num_subblocks); i++) {
+		length = tas25xx_process_block(tas2562,
+					&tas2562->fw_data->config_info[offset]);
+		if (length < 0)
+			return length;
+
+		offset += length;
+	}
+
+	/* Reset Book to 0 */
+	regmap_write(tas2562->regmap, TAS2562_BOOK_CTRL, 0);
+
+	return 0;
+}
+
+static ssize_t write_config_store(struct device *dev,
+				struct device_attribute *tas25xx_attr,
+				const char *buf, size_t size)
+{
+	struct tas2562_data *tas25xx = dev_get_drvdata(dev);
+	struct tas25xx_fw_hdr *fw_hdr = tas25xx->fw_data->fw_hdr;
+	long configs;
+	int ret;
+
+	ret = kstrtol(buf, 10, &configs);
+	if (ret != 0)
+		return ret;
+
+	if (configs < 1 || configs > cpu_to_be32(fw_hdr->num_configs))
+		return -EINVAL;
+
+	configs--;
+	ret =  tas25xx_write_config(tas25xx, configs);
+	if (!ret)
+		ret = size;
+
+	return ret;
+}
+static DEVICE_ATTR_WO(write_config);
+
+static ssize_t write_program_store(struct device *dev,
+				struct device_attribute *tas25xx_attr,
+				const char *buf, size_t size)
+{
+	struct tas2562_data *tas25xx = dev_get_drvdata(dev);
+	struct tas25xx_fw_hdr *fw_hdr = tas25xx->fw_data->fw_hdr;
+	long program;
+	int ret;
+
+	ret = kstrtol(buf, 10, &program);
+	if (ret != 0)
+		return ret;
+
+	if (program < 1 || program > cpu_to_be32(fw_hdr->num_programs))
+		return -EINVAL;
+
+	program--;
+	ret =  tas25xx_write_program(tas25xx, program);
+	if (!ret)
+		ret = size;
+
+	return ret;
+}
+static DEVICE_ATTR_WO(write_program);
+
+static ssize_t enable_program_show(struct device *dev,
+			      struct device_attribute *tas25xx_attr,
+			      char *buf)
+{
+	struct tas2562_data *tas25xx = dev_get_drvdata(dev);
+	int mode;
+
+	regmap_read(tas25xx->regmap, TAS25XX_DSP_MODE, &mode);
+
+	return sprintf(buf, "0x%X\n", mode);
+}
+
+static ssize_t enable_program_store(struct device *dev,
+				struct device_attribute *tas25xx_attr,
+				const char *buf, size_t size)
+{
+	struct tas2562_data *tas25xx = dev_get_drvdata(dev);
+	long mode;
+	int ret;
+
+	ret = kstrtol(buf, 10, &mode);
+	if (ret != 0)
+		return ret;
+
+	if (mode)
+		ret = regmap_write(tas25xx->regmap, TAS25XX_DSP_MODE, mode);
+	else
+		ret = regmap_write(tas25xx->regmap, TAS25XX_DSP_MODE, 0);
+
+	if (!ret)
+		ret = size;
+
+	return ret;
+
+}
+static DEVICE_ATTR_RW(enable_program);
+
+static ssize_t num_configs_show(struct device *dev,
+			      struct device_attribute *tas25xx_attr,
+			      char *buf)
+{
+	struct tas2562_data *tas25xx = dev_get_drvdata(dev);
+	struct tas25xx_fw_hdr *fw_hdr = tas25xx->fw_data->fw_hdr;
+
+	return sprintf(buf, "%d\n", cpu_to_be32(fw_hdr->num_configs));
+}
+static DEVICE_ATTR_RO(num_configs);
+
+static ssize_t num_programs_show(struct device *dev,
+			      struct device_attribute *tas25xx_attr,
+			      char *buf)
+{
+	struct tas2562_data *tas25xx = dev_get_drvdata(dev);
+	struct tas25xx_fw_hdr *fw_hdr = tas25xx->fw_data->fw_hdr;
+
+	return sprintf(buf, "%d\n", cpu_to_be32(fw_hdr->num_programs));
+}
+static DEVICE_ATTR_RO(num_programs);
+
+static struct attribute *tas25xx_fw_attrs[] = {
+	&dev_attr_num_programs.attr,
+	&dev_attr_num_configs.attr,
+	&dev_attr_write_config.attr,
+	&dev_attr_write_program.attr,
+	&dev_attr_enable_program.attr,
+	NULL,
+};
+
+static const struct attribute_group tas25xx_fw_attr_group = {
+	.attrs	= tas25xx_fw_attrs,
+};
+
+int tas25xx_init_fw(struct tas2562_data *tas2562, const struct firmware *fw)
+{
+	u32 total_prog_sz = 0;
+	u32 total_config_sz = 0;
+	int hdr_size = sizeof(struct tas25xx_fw_hdr);
+	int i;
+	u8 *out;
+	int ret;
+
+	if (!fw->size)
+		return -ENODATA;
+
+	out = devm_kzalloc(tas2562->dev, fw->size, GFP_KERNEL);
+	if (!out)
+		return -ENOMEM;
+
+	memcpy(out, &fw->data[0], fw->size);
+	tas2562->fw_data = (struct tas25xx_fw_data *)out;
+
+	tas2562->fw_data->fw_hdr = devm_kzalloc(tas2562->dev, hdr_size,
+						GFP_KERNEL);
+	if (!tas2562->fw_data->fw_hdr)
+		return -ENOMEM;
+
+	memcpy(tas2562->fw_data->fw_hdr, &fw->data[0], hdr_size);
+
+	for (i = 0; i < cpu_to_be32(tas2562->fw_data->fw_hdr->num_programs); i++)
+		total_prog_sz += cpu_to_be32(tas2562->fw_data->fw_hdr->prog_size[i]);
+
+	for (i = 0; i < cpu_to_be32(tas2562->fw_data->fw_hdr->num_configs); i++)
+		total_config_sz += cpu_to_be32(tas2562->fw_data->fw_hdr->config_size[i]);
+
+	tas2562->fw_data->prog_info = devm_kzalloc(tas2562->dev, total_prog_sz,
+						   GFP_KERNEL);
+	if (!tas2562->fw_data->prog_info)
+		return -ENOMEM;
+
+	memcpy(tas2562->fw_data->prog_info, &fw->data[hdr_size], total_prog_sz);
+
+	tas2562->fw_data->config_info = devm_kzalloc(tas2562->dev,
+						     total_config_sz,
+						     GFP_KERNEL);
+	if (!tas2562->fw_data->config_info)
+		return -ENOMEM;
+
+	hdr_size += total_prog_sz;
+	memcpy(tas2562->fw_data->config_info, &fw->data[hdr_size],
+	       total_config_sz);
+
+	/* Create SysFS files */
+	ret = device_add_group(tas2562->dev, &tas25xx_fw_attr_group);
+	if (ret)
+		dev_info(tas2562->dev, "error creating sysfs files\n");
+
+	release_firmware(fw);
+
+	return 0;
+}
+
diff --git a/sound/soc/codecs/tas25xx_dsp_loader.h b/sound/soc/codecs/tas25xx_dsp_loader.h
new file mode 100644
index 000000000000..01d002da928f
--- /dev/null
+++ b/sound/soc/codecs/tas25xx_dsp_loader.h
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * tas25xx_dsp_loader.h - Texas Instruments TAS25xx Mono Audio Amplifier
+ *
+ * Copyright (C) 2020 Texas Instruments Incorporated -  http://www.ti.com
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ */
+
+#ifndef _TAS25XX_DSP_LOADER_H
+#define _TAS25XX_DSP_LOADER_H
+
+#include "tas2562.h"
+
+#define TAS25XX_NAME_SIZE	64
+#define TAS25XX_PROG_SIZE	5
+#define TAS25XX_CONFIG_SIZE	10
+
+#define TAS25XX_SINGLE_COMMAND	0x7f
+#define TAS25XX_OFFSET_SHIFT	3
+
+#define TAS25XX_BLK_HDR_SZ	4
+
+#define TAS25XX_CMD_SING_W	0x1
+#define TAS25XX_CMD_BURST	0x2
+#define TAS25XX_CMD_DELAY	0x3
+
+struct tas25xx_cmd_data {
+	u16 cmd_type;
+	u16 length;
+	u8 book;
+	u8 page;
+	u8 offset;
+};
+
+struct tas25xx_block_data {
+	u32 block_type;
+	u16 pram_checksum;
+	u16 yram_checksum;
+	u32 block_size;
+	u32 num_subblocks;
+};
+
+struct tas25xx_program_info {
+	char name[TAS25XX_NAME_SIZE];
+	u8 app_mode;
+	u8 pdm_i2s_mode;
+	u8 isns_pd;
+	u8 vsns_pd;
+	u8 reserved_1;
+	u16 reserved_2;
+	u8 ldg_power_up;
+	struct tas25xx_block_data blk_data;
+};
+
+struct tas25xx_config_info {
+	char name[TAS25XX_NAME_SIZE];
+	u16 devices;
+	u16 program;
+	u32 samp_rate;
+	u16 clk_src;
+	u16 sbclk_fs_ratio;
+	u32 clk_freq;
+	u32 num_blocks;
+	struct tas25xx_block_data blk_data;
+};
+
+struct tas25xx_fw_hdr {
+	u32 magic_num;
+	u32 image_size;
+	u32 checksum;
+	u32 version_num;
+	u32 dsp_version;
+	u32 drv_fw_version;
+	u32 timestamp;
+	char firmware_name[TAS25XX_NAME_SIZE];
+	u16 dev_family;
+	u16 dev_subfamily;
+	u32 num_programs;
+	u32 prog_size[TAS25XX_PROG_SIZE];
+	u32 num_configs;
+	u32 config_size[TAS25XX_CONFIG_SIZE];
+};
+
+struct tas25xx_fw_data {
+	struct tas25xx_fw_hdr *fw_hdr;
+	u8 *config_info;
+	u8 *prog_info;
+};
+
+int tas25xx_init_fw(struct tas2562_data *tas2562, const struct firmware *fw);
+
+#endif /* _TAS25XX_DSP_LOADER_H */
