diff options
Diffstat (limited to 'sound/soc/samsung')
-rw-r--r-- | sound/soc/samsung/Kconfig | 6 | ||||
-rw-r--r-- | sound/soc/samsung/dma.c | 3 | ||||
-rw-r--r-- | sound/soc/samsung/dma.h | 1 | ||||
-rw-r--r-- | sound/soc/samsung/i2s.c | 267 | ||||
-rw-r--r-- | sound/soc/samsung/i2s.h | 7 | ||||
-rw-r--r-- | sound/soc/samsung/smdk_wm8580.c | 7 | ||||
-rw-r--r-- | sound/soc/samsung/smdk_wm8994.c | 30 |
7 files changed, 256 insertions, 65 deletions
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 3c7c3a59ed39..90e7e6653233 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
@@ -63,7 +63,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8580 | |||
63 | 63 | ||
64 | config SND_SOC_SAMSUNG_SMDK_WM8994 | 64 | config SND_SOC_SAMSUNG_SMDK_WM8994 |
65 | tristate "SoC I2S Audio support for WM8994 on SMDK" | 65 | tristate "SoC I2S Audio support for WM8994 on SMDK" |
66 | depends on SND_SOC_SAMSUNG && (MACH_SMDKV310 || MACH_SMDKC210 || MACH_SMDK4212) | 66 | depends on SND_SOC_SAMSUNG |
67 | depends on I2C=y && GENERIC_HARDIRQS | 67 | depends on I2C=y && GENERIC_HARDIRQS |
68 | select MFD_WM8994 | 68 | select MFD_WM8994 |
69 | select SND_SOC_WM8994 | 69 | select SND_SOC_WM8994 |
@@ -162,7 +162,7 @@ config SND_SOC_GONI_AQUILA_WM8994 | |||
162 | 162 | ||
163 | config SND_SOC_SAMSUNG_SMDK_SPDIF | 163 | config SND_SOC_SAMSUNG_SMDK_SPDIF |
164 | tristate "SoC S/PDIF Audio support for SMDK" | 164 | tristate "SoC S/PDIF Audio support for SMDK" |
165 | depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310 || MACH_SMDK4212) | 165 | depends on SND_SOC_SAMSUNG |
166 | select SND_SAMSUNG_SPDIF | 166 | select SND_SAMSUNG_SPDIF |
167 | help | 167 | help |
168 | Say Y if you want to add support for SoC S/PDIF audio on the SMDK. | 168 | Say Y if you want to add support for SoC S/PDIF audio on the SMDK. |
@@ -177,7 +177,7 @@ config SND_SOC_SMDK_WM8580_PCM | |||
177 | 177 | ||
178 | config SND_SOC_SMDK_WM8994_PCM | 178 | config SND_SOC_SMDK_WM8994_PCM |
179 | tristate "SoC PCM Audio support for WM8994 on SMDK" | 179 | tristate "SoC PCM Audio support for WM8994 on SMDK" |
180 | depends on SND_SOC_SAMSUNG && (MACH_SMDKC210 || MACH_SMDKV310 || MACH_SMDK4212) | 180 | depends on SND_SOC_SAMSUNG |
181 | depends on I2C=y && GENERIC_HARDIRQS | 181 | depends on I2C=y && GENERIC_HARDIRQS |
182 | select MFD_WM8994 | 182 | select MFD_WM8994 |
183 | select SND_SOC_WM8994 | 183 | select SND_SOC_WM8994 |
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index db87628d7630..21b79262010e 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c | |||
@@ -174,7 +174,8 @@ static int dma_hw_params(struct snd_pcm_substream *substream, | |||
174 | config.width = prtd->params->dma_size; | 174 | config.width = prtd->params->dma_size; |
175 | config.fifo = prtd->params->dma_addr; | 175 | config.fifo = prtd->params->dma_addr; |
176 | prtd->params->ch = prtd->params->ops->request( | 176 | prtd->params->ch = prtd->params->ops->request( |
177 | prtd->params->channel, &req); | 177 | prtd->params->channel, &req, rtd->cpu_dai->dev, |
178 | prtd->params->ch_name); | ||
178 | prtd->params->ops->config(prtd->params->ch, &config); | 179 | prtd->params->ops->config(prtd->params->ch, &config); |
179 | } | 180 | } |
180 | 181 | ||
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 73d8c7c8a1e8..189a7a6d5020 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h | |||
@@ -19,6 +19,7 @@ struct s3c_dma_params { | |||
19 | int dma_size; /* Size of the DMA transfer */ | 19 | int dma_size; /* Size of the DMA transfer */ |
20 | unsigned ch; | 20 | unsigned ch; |
21 | struct samsung_dma_ops *ops; | 21 | struct samsung_dma_ops *ops; |
22 | char *ch_name; | ||
22 | }; | 23 | }; |
23 | 24 | ||
24 | int asoc_dma_platform_register(struct device *dev); | 25 | int asoc_dma_platform_register(struct device *dev); |
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index d2d124f1dd1b..d7231e336a7c 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -15,11 +15,15 @@ | |||
15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/of.h> | ||
19 | #include <linux/of_gpio.h> | ||
18 | #include <linux/pm_runtime.h> | 20 | #include <linux/pm_runtime.h> |
19 | 21 | ||
20 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
21 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
22 | 24 | ||
25 | #include <mach/dma.h> | ||
26 | |||
23 | #include <linux/platform_data/asoc-s3c.h> | 27 | #include <linux/platform_data/asoc-s3c.h> |
24 | 28 | ||
25 | #include "dma.h" | 29 | #include "dma.h" |
@@ -29,6 +33,15 @@ | |||
29 | 33 | ||
30 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | 34 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) |
31 | 35 | ||
36 | enum samsung_dai_type { | ||
37 | TYPE_PRI, | ||
38 | TYPE_SEC, | ||
39 | }; | ||
40 | |||
41 | struct samsung_i2s_dai_data { | ||
42 | int dai_type; | ||
43 | }; | ||
44 | |||
32 | struct i2s_dai { | 45 | struct i2s_dai { |
33 | /* Platform device for this DAI */ | 46 | /* Platform device for this DAI */ |
34 | struct platform_device *pdev; | 47 | struct platform_device *pdev; |
@@ -66,6 +79,7 @@ struct i2s_dai { | |||
66 | u32 suspend_i2smod; | 79 | u32 suspend_i2smod; |
67 | u32 suspend_i2scon; | 80 | u32 suspend_i2scon; |
68 | u32 suspend_i2spsr; | 81 | u32 suspend_i2spsr; |
82 | unsigned long gpios[7]; /* i2s gpio line numbers */ | ||
69 | }; | 83 | }; |
70 | 84 | ||
71 | /* Lock for cross i/f checks */ | 85 | /* Lock for cross i/f checks */ |
@@ -651,6 +665,9 @@ static int i2s_startup(struct snd_pcm_substream *substream, | |||
651 | /* Enforce set_sysclk in Master mode */ | 665 | /* Enforce set_sysclk in Master mode */ |
652 | i2s->rclk_srcrate = 0; | 666 | i2s->rclk_srcrate = 0; |
653 | 667 | ||
668 | if (!any_active(i2s) && (i2s->quirks & QUIRK_NEED_RSTCLR)) | ||
669 | writel(CON_RSTCLR, i2s->addr + I2SCON); | ||
670 | |||
654 | spin_unlock_irqrestore(&lock, flags); | 671 | spin_unlock_irqrestore(&lock, flags); |
655 | 672 | ||
656 | return 0; | 673 | return 0; |
@@ -981,8 +998,7 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) | |||
981 | i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; | 998 | i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS; |
982 | } else { /* Create a new platform_device for Secondary */ | 999 | } else { /* Create a new platform_device for Secondary */ |
983 | i2s->pdev = platform_device_register_resndata(NULL, | 1000 | i2s->pdev = platform_device_register_resndata(NULL, |
984 | pdev->name, pdev->id + SAMSUNG_I2S_SECOFF, | 1001 | "samsung-i2s-sec", -1, NULL, 0, NULL, 0); |
985 | NULL, 0, NULL, 0); | ||
986 | if (IS_ERR(i2s->pdev)) | 1002 | if (IS_ERR(i2s->pdev)) |
987 | return NULL; | 1003 | return NULL; |
988 | } | 1004 | } |
@@ -993,18 +1009,103 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) | |||
993 | return i2s; | 1009 | return i2s; |
994 | } | 1010 | } |
995 | 1011 | ||
1012 | #ifdef CONFIG_OF | ||
1013 | static int samsung_i2s_parse_dt_gpio(struct i2s_dai *i2s) | ||
1014 | { | ||
1015 | struct device *dev = &i2s->pdev->dev; | ||
1016 | int index, gpio, ret; | ||
1017 | |||
1018 | for (index = 0; index < 7; index++) { | ||
1019 | gpio = of_get_gpio(dev->of_node, index); | ||
1020 | if (!gpio_is_valid(gpio)) { | ||
1021 | dev_err(dev, "invalid gpio[%d]: %d\n", index, gpio); | ||
1022 | goto free_gpio; | ||
1023 | } | ||
1024 | |||
1025 | ret = gpio_request(gpio, dev_name(dev)); | ||
1026 | if (ret) { | ||
1027 | dev_err(dev, "gpio [%d] request failed\n", gpio); | ||
1028 | goto free_gpio; | ||
1029 | } | ||
1030 | i2s->gpios[index] = gpio; | ||
1031 | } | ||
1032 | return 0; | ||
1033 | |||
1034 | free_gpio: | ||
1035 | while (--index >= 0) | ||
1036 | gpio_free(i2s->gpios[index]); | ||
1037 | return -EINVAL; | ||
1038 | } | ||
1039 | |||
1040 | static void samsung_i2s_dt_gpio_free(struct i2s_dai *i2s) | ||
1041 | { | ||
1042 | unsigned int index; | ||
1043 | for (index = 0; index < 7; index++) | ||
1044 | gpio_free(i2s->gpios[index]); | ||
1045 | } | ||
1046 | #else | ||
1047 | static int samsung_i2s_parse_dt_gpio(struct i2s_dai *dai) | ||
1048 | { | ||
1049 | return -EINVAL; | ||
1050 | } | ||
1051 | |||
1052 | static void samsung_i2s_dt_gpio_free(struct i2s_dai *dai) | ||
1053 | { | ||
1054 | } | ||
1055 | |||
1056 | #endif | ||
1057 | |||
1058 | static const struct of_device_id exynos_i2s_match[]; | ||
1059 | |||
1060 | static inline int samsung_i2s_get_driver_data(struct platform_device *pdev) | ||
1061 | { | ||
1062 | #ifdef CONFIG_OF | ||
1063 | struct samsung_i2s_dai_data *data; | ||
1064 | if (pdev->dev.of_node) { | ||
1065 | const struct of_device_id *match; | ||
1066 | match = of_match_node(exynos_i2s_match, pdev->dev.of_node); | ||
1067 | data = (struct samsung_i2s_dai_data *) match->data; | ||
1068 | return data->dai_type; | ||
1069 | } else | ||
1070 | #endif | ||
1071 | return platform_get_device_id(pdev)->driver_data; | ||
1072 | } | ||
1073 | |||
1074 | #ifdef CONFIG_PM_RUNTIME | ||
1075 | static int i2s_runtime_suspend(struct device *dev) | ||
1076 | { | ||
1077 | struct i2s_dai *i2s = dev_get_drvdata(dev); | ||
1078 | |||
1079 | clk_disable_unprepare(i2s->clk); | ||
1080 | |||
1081 | return 0; | ||
1082 | } | ||
1083 | |||
1084 | static int i2s_runtime_resume(struct device *dev) | ||
1085 | { | ||
1086 | struct i2s_dai *i2s = dev_get_drvdata(dev); | ||
1087 | |||
1088 | clk_prepare_enable(i2s->clk); | ||
1089 | |||
1090 | return 0; | ||
1091 | } | ||
1092 | #endif /* CONFIG_PM_RUNTIME */ | ||
1093 | |||
996 | static int samsung_i2s_probe(struct platform_device *pdev) | 1094 | static int samsung_i2s_probe(struct platform_device *pdev) |
997 | { | 1095 | { |
998 | u32 dma_pl_chan, dma_cp_chan, dma_pl_sec_chan; | ||
999 | struct i2s_dai *pri_dai, *sec_dai = NULL; | 1096 | struct i2s_dai *pri_dai, *sec_dai = NULL; |
1000 | struct s3c_audio_pdata *i2s_pdata; | 1097 | struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; |
1001 | struct samsung_i2s *i2s_cfg; | 1098 | struct samsung_i2s *i2s_cfg = NULL; |
1002 | struct resource *res; | 1099 | struct resource *res; |
1003 | u32 regs_base, quirks; | 1100 | u32 regs_base, quirks = 0, idma_addr = 0; |
1101 | struct device_node *np = pdev->dev.of_node; | ||
1102 | enum samsung_dai_type samsung_dai_type; | ||
1004 | int ret = 0; | 1103 | int ret = 0; |
1005 | 1104 | ||
1006 | /* Call during Seconday interface registration */ | 1105 | /* Call during Seconday interface registration */ |
1007 | if (pdev->id >= SAMSUNG_I2S_SECOFF) { | 1106 | samsung_dai_type = samsung_i2s_get_driver_data(pdev); |
1107 | |||
1108 | if (samsung_dai_type == TYPE_SEC) { | ||
1008 | sec_dai = dev_get_drvdata(&pdev->dev); | 1109 | sec_dai = dev_get_drvdata(&pdev->dev); |
1009 | snd_soc_register_dai(&sec_dai->pdev->dev, | 1110 | snd_soc_register_dai(&sec_dai->pdev->dev, |
1010 | &sec_dai->i2s_dai_drv); | 1111 | &sec_dai->i2s_dai_drv); |
@@ -1012,31 +1113,60 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1012 | return 0; | 1113 | return 0; |
1013 | } | 1114 | } |
1014 | 1115 | ||
1015 | i2s_pdata = pdev->dev.platform_data; | 1116 | pri_dai = i2s_alloc_dai(pdev, false); |
1016 | if (i2s_pdata == NULL) { | 1117 | if (!pri_dai) { |
1017 | dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); | 1118 | dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); |
1018 | return -EINVAL; | 1119 | return -ENOMEM; |
1019 | } | 1120 | } |
1020 | 1121 | ||
1021 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 1122 | if (!np) { |
1022 | if (!res) { | 1123 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
1023 | dev_err(&pdev->dev, "Unable to get I2S-TX dma resource\n"); | 1124 | if (!res) { |
1024 | return -ENXIO; | 1125 | dev_err(&pdev->dev, |
1025 | } | 1126 | "Unable to get I2S-TX dma resource\n"); |
1026 | dma_pl_chan = res->start; | 1127 | return -ENXIO; |
1128 | } | ||
1129 | pri_dai->dma_playback.channel = res->start; | ||
1027 | 1130 | ||
1028 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 1131 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
1029 | if (!res) { | 1132 | if (!res) { |
1030 | dev_err(&pdev->dev, "Unable to get I2S-RX dma resource\n"); | 1133 | dev_err(&pdev->dev, |
1031 | return -ENXIO; | 1134 | "Unable to get I2S-RX dma resource\n"); |
1032 | } | 1135 | return -ENXIO; |
1033 | dma_cp_chan = res->start; | 1136 | } |
1137 | pri_dai->dma_capture.channel = res->start; | ||
1034 | 1138 | ||
1035 | res = platform_get_resource(pdev, IORESOURCE_DMA, 2); | 1139 | if (i2s_pdata == NULL) { |
1036 | if (res) | 1140 | dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); |
1037 | dma_pl_sec_chan = res->start; | 1141 | return -EINVAL; |
1038 | else | 1142 | } |
1039 | dma_pl_sec_chan = 0; | 1143 | |
1144 | if (&i2s_pdata->type) | ||
1145 | i2s_cfg = &i2s_pdata->type.i2s; | ||
1146 | |||
1147 | if (i2s_cfg) { | ||
1148 | quirks = i2s_cfg->quirks; | ||
1149 | idma_addr = i2s_cfg->idma_addr; | ||
1150 | } | ||
1151 | } else { | ||
1152 | if (of_find_property(np, "samsung,supports-6ch", NULL)) | ||
1153 | quirks |= QUIRK_PRI_6CHAN; | ||
1154 | |||
1155 | if (of_find_property(np, "samsung,supports-secdai", NULL)) | ||
1156 | quirks |= QUIRK_SEC_DAI; | ||
1157 | |||
1158 | if (of_find_property(np, "samsung,supports-rstclr", NULL)) | ||
1159 | quirks |= QUIRK_NEED_RSTCLR; | ||
1160 | |||
1161 | if (of_property_read_u32(np, "samsung,idma-addr", | ||
1162 | &idma_addr)) { | ||
1163 | if (quirks & QUIRK_SEC_DAI) { | ||
1164 | dev_err(&pdev->dev, "idma address is not"\ | ||
1165 | "specified"); | ||
1166 | return -EINVAL; | ||
1167 | } | ||
1168 | } | ||
1169 | } | ||
1040 | 1170 | ||
1041 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1171 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1042 | if (!res) { | 1172 | if (!res) { |
@@ -1051,24 +1181,14 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1051 | } | 1181 | } |
1052 | regs_base = res->start; | 1182 | regs_base = res->start; |
1053 | 1183 | ||
1054 | i2s_cfg = &i2s_pdata->type.i2s; | ||
1055 | quirks = i2s_cfg->quirks; | ||
1056 | |||
1057 | pri_dai = i2s_alloc_dai(pdev, false); | ||
1058 | if (!pri_dai) { | ||
1059 | dev_err(&pdev->dev, "Unable to alloc I2S_pri\n"); | ||
1060 | ret = -ENOMEM; | ||
1061 | goto err; | ||
1062 | } | ||
1063 | |||
1064 | pri_dai->dma_playback.dma_addr = regs_base + I2STXD; | 1184 | pri_dai->dma_playback.dma_addr = regs_base + I2STXD; |
1065 | pri_dai->dma_capture.dma_addr = regs_base + I2SRXD; | 1185 | pri_dai->dma_capture.dma_addr = regs_base + I2SRXD; |
1066 | pri_dai->dma_playback.client = | 1186 | pri_dai->dma_playback.client = |
1067 | (struct s3c2410_dma_client *)&pri_dai->dma_playback; | 1187 | (struct s3c2410_dma_client *)&pri_dai->dma_playback; |
1188 | pri_dai->dma_playback.ch_name = "tx"; | ||
1068 | pri_dai->dma_capture.client = | 1189 | pri_dai->dma_capture.client = |
1069 | (struct s3c2410_dma_client *)&pri_dai->dma_capture; | 1190 | (struct s3c2410_dma_client *)&pri_dai->dma_capture; |
1070 | pri_dai->dma_playback.channel = dma_pl_chan; | 1191 | pri_dai->dma_capture.ch_name = "rx"; |
1071 | pri_dai->dma_capture.channel = dma_cp_chan; | ||
1072 | pri_dai->dma_playback.dma_size = 4; | 1192 | pri_dai->dma_playback.dma_size = 4; |
1073 | pri_dai->dma_capture.dma_size = 4; | 1193 | pri_dai->dma_capture.dma_size = 4; |
1074 | pri_dai->base = regs_base; | 1194 | pri_dai->base = regs_base; |
@@ -1087,20 +1207,34 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1087 | sec_dai->dma_playback.dma_addr = regs_base + I2STXDS; | 1207 | sec_dai->dma_playback.dma_addr = regs_base + I2STXDS; |
1088 | sec_dai->dma_playback.client = | 1208 | sec_dai->dma_playback.client = |
1089 | (struct s3c2410_dma_client *)&sec_dai->dma_playback; | 1209 | (struct s3c2410_dma_client *)&sec_dai->dma_playback; |
1090 | /* Use iDMA always if SysDMA not provided */ | 1210 | sec_dai->dma_playback.ch_name = "tx-sec"; |
1091 | sec_dai->dma_playback.channel = dma_pl_sec_chan ? : -1; | 1211 | |
1212 | if (!np) { | ||
1213 | res = platform_get_resource(pdev, IORESOURCE_DMA, 2); | ||
1214 | if (res) | ||
1215 | sec_dai->dma_playback.channel = res->start; | ||
1216 | } | ||
1217 | |||
1092 | sec_dai->dma_playback.dma_size = 4; | 1218 | sec_dai->dma_playback.dma_size = 4; |
1093 | sec_dai->base = regs_base; | 1219 | sec_dai->base = regs_base; |
1094 | sec_dai->quirks = quirks; | 1220 | sec_dai->quirks = quirks; |
1095 | sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr; | 1221 | sec_dai->idma_playback.dma_addr = idma_addr; |
1096 | sec_dai->pri_dai = pri_dai; | 1222 | sec_dai->pri_dai = pri_dai; |
1097 | pri_dai->sec_dai = sec_dai; | 1223 | pri_dai->sec_dai = sec_dai; |
1098 | } | 1224 | } |
1099 | 1225 | ||
1100 | if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { | 1226 | if (np) { |
1101 | dev_err(&pdev->dev, "Unable to configure gpio\n"); | 1227 | if (samsung_i2s_parse_dt_gpio(pri_dai)) { |
1102 | ret = -EINVAL; | 1228 | dev_err(&pdev->dev, "Unable to configure gpio\n"); |
1103 | goto err; | 1229 | ret = -EINVAL; |
1230 | goto err; | ||
1231 | } | ||
1232 | } else { | ||
1233 | if (i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) { | ||
1234 | dev_err(&pdev->dev, "Unable to configure gpio\n"); | ||
1235 | ret = -EINVAL; | ||
1236 | goto err; | ||
1237 | } | ||
1104 | } | 1238 | } |
1105 | 1239 | ||
1106 | snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv); | 1240 | snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv); |
@@ -1120,10 +1254,14 @@ static int samsung_i2s_remove(struct platform_device *pdev) | |||
1120 | { | 1254 | { |
1121 | struct i2s_dai *i2s, *other; | 1255 | struct i2s_dai *i2s, *other; |
1122 | struct resource *res; | 1256 | struct resource *res; |
1257 | struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; | ||
1123 | 1258 | ||
1124 | i2s = dev_get_drvdata(&pdev->dev); | 1259 | i2s = dev_get_drvdata(&pdev->dev); |
1125 | other = i2s->pri_dai ? : i2s->sec_dai; | 1260 | other = i2s->pri_dai ? : i2s->sec_dai; |
1126 | 1261 | ||
1262 | if (!i2s_pdata->cfg_gpio && pdev->dev.of_node) | ||
1263 | samsung_i2s_dt_gpio_free(i2s->pri_dai); | ||
1264 | |||
1127 | if (other) { | 1265 | if (other) { |
1128 | other->pri_dai = NULL; | 1266 | other->pri_dai = NULL; |
1129 | other->sec_dai = NULL; | 1267 | other->sec_dai = NULL; |
@@ -1143,12 +1281,47 @@ static int samsung_i2s_remove(struct platform_device *pdev) | |||
1143 | return 0; | 1281 | return 0; |
1144 | } | 1282 | } |
1145 | 1283 | ||
1284 | static struct platform_device_id samsung_i2s_driver_ids[] = { | ||
1285 | { | ||
1286 | .name = "samsung-i2s", | ||
1287 | .driver_data = TYPE_PRI, | ||
1288 | }, { | ||
1289 | .name = "samsung-i2s-sec", | ||
1290 | .driver_data = TYPE_SEC, | ||
1291 | }, | ||
1292 | {}, | ||
1293 | }; | ||
1294 | MODULE_DEVICE_TABLE(platform, samsung-i2s-driver-ids); | ||
1295 | |||
1296 | #ifdef CONFIG_OF | ||
1297 | static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = { | ||
1298 | [TYPE_PRI] = { TYPE_PRI }, | ||
1299 | [TYPE_SEC] = { TYPE_SEC }, | ||
1300 | }; | ||
1301 | |||
1302 | static const struct of_device_id exynos_i2s_match[] = { | ||
1303 | { .compatible = "samsung,i2s-v5", | ||
1304 | .data = &samsung_i2s_dai_data_array[TYPE_PRI], | ||
1305 | }, | ||
1306 | {}, | ||
1307 | }; | ||
1308 | MODULE_DEVICE_TABLE(of, exynos_i2s_match); | ||
1309 | #endif | ||
1310 | |||
1311 | static const struct dev_pm_ops samsung_i2s_pm = { | ||
1312 | SET_RUNTIME_PM_OPS(i2s_runtime_suspend, | ||
1313 | i2s_runtime_resume, NULL) | ||
1314 | }; | ||
1315 | |||
1146 | static struct platform_driver samsung_i2s_driver = { | 1316 | static struct platform_driver samsung_i2s_driver = { |
1147 | .probe = samsung_i2s_probe, | 1317 | .probe = samsung_i2s_probe, |
1148 | .remove = samsung_i2s_remove, | 1318 | .remove = samsung_i2s_remove, |
1319 | .id_table = samsung_i2s_driver_ids, | ||
1149 | .driver = { | 1320 | .driver = { |
1150 | .name = "samsung-i2s", | 1321 | .name = "samsung-i2s", |
1151 | .owner = THIS_MODULE, | 1322 | .owner = THIS_MODULE, |
1323 | .of_match_table = of_match_ptr(exynos_i2s_match), | ||
1324 | .pm = &samsung_i2s_pm, | ||
1152 | }, | 1325 | }, |
1153 | }; | 1326 | }; |
1154 | 1327 | ||
diff --git a/sound/soc/samsung/i2s.h b/sound/soc/samsung/i2s.h index d420a7ca56ca..7966afc934db 100644 --- a/sound/soc/samsung/i2s.h +++ b/sound/soc/samsung/i2s.h | |||
@@ -13,13 +13,6 @@ | |||
13 | #ifndef __SND_SOC_SAMSUNG_I2S_H | 13 | #ifndef __SND_SOC_SAMSUNG_I2S_H |
14 | #define __SND_SOC_SAMSUNG_I2S_H | 14 | #define __SND_SOC_SAMSUNG_I2S_H |
15 | 15 | ||
16 | /* | ||
17 | * Maximum number of I2S blocks that any SoC can have. | ||
18 | * The secondary interface of a CPU dai(if there exists any), | ||
19 | * is indexed at [cpu-dai's ID + SAMSUNG_I2S_SECOFF] | ||
20 | */ | ||
21 | #define SAMSUNG_I2S_SECOFF 4 | ||
22 | |||
23 | #define SAMSUNG_I2S_DIV_BCLK 1 | 16 | #define SAMSUNG_I2S_DIV_BCLK 1 |
24 | 17 | ||
25 | #define SAMSUNG_I2S_RCLKSRC_0 0 | 18 | #define SAMSUNG_I2S_RCLKSRC_0 0 |
diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index 7e2b710763be..7a16b32ed673 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c | |||
@@ -193,9 +193,9 @@ static struct snd_soc_dai_link smdk_dai[] = { | |||
193 | [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ | 193 | [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ |
194 | .name = "Sec_FIFO TX", | 194 | .name = "Sec_FIFO TX", |
195 | .stream_name = "Playback", | 195 | .stream_name = "Playback", |
196 | .cpu_dai_name = "samsung-i2s.x", | 196 | .cpu_dai_name = "samsung-i2s-sec", |
197 | .codec_dai_name = "wm8580-hifi-playback", | 197 | .codec_dai_name = "wm8580-hifi-playback", |
198 | .platform_name = "samsung-i2s.x", | 198 | .platform_name = "samsung-i2s-sec", |
199 | .codec_name = "wm8580.0-001b", | 199 | .codec_name = "wm8580.0-001b", |
200 | .ops = &smdk_ops, | 200 | .ops = &smdk_ops, |
201 | }, | 201 | }, |
@@ -223,9 +223,6 @@ static int __init smdk_audio_init(void) | |||
223 | if (machine_is_smdkc100() | 223 | if (machine_is_smdkc100() |
224 | || machine_is_smdkv210() || machine_is_smdkc110()) { | 224 | || machine_is_smdkv210() || machine_is_smdkc110()) { |
225 | smdk.num_links = 3; | 225 | smdk.num_links = 3; |
226 | /* Secondary is at offset SAMSUNG_I2S_SECOFF from Primary */ | ||
227 | str = (char *)smdk_dai[SEC_PLAYBACK].cpu_dai_name; | ||
228 | str[strlen(str) - 1] = '0' + SAMSUNG_I2S_SECOFF; | ||
229 | } else if (machine_is_smdk6410()) { | 226 | } else if (machine_is_smdk6410()) { |
230 | str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; | 227 | str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; |
231 | str[strlen(str) - 1] = '2'; | 228 | str[strlen(str) - 1] = '2'; |
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index b0d0ab8bff5a..581ea4a06fc6 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "../codecs/wm8994.h" | 10 | #include "../codecs/wm8994.h" |
11 | #include <sound/pcm_params.h> | 11 | #include <sound/pcm_params.h> |
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/of.h> | ||
13 | 14 | ||
14 | /* | 15 | /* |
15 | * Default CFG switch settings to use this driver: | 16 | * Default CFG switch settings to use this driver: |
@@ -134,9 +135,9 @@ static struct snd_soc_dai_link smdk_dai[] = { | |||
134 | }, { /* Sec_Fifo Playback i/f */ | 135 | }, { /* Sec_Fifo Playback i/f */ |
135 | .name = "Sec_FIFO TX", | 136 | .name = "Sec_FIFO TX", |
136 | .stream_name = "Sec_Dai", | 137 | .stream_name = "Sec_Dai", |
137 | .cpu_dai_name = "samsung-i2s.4", | 138 | .cpu_dai_name = "samsung-i2s-sec", |
138 | .codec_dai_name = "wm8994-aif1", | 139 | .codec_dai_name = "wm8994-aif1", |
139 | .platform_name = "samsung-i2s.4", | 140 | .platform_name = "samsung-i2s-sec", |
140 | .codec_name = "wm8994-codec", | 141 | .codec_name = "wm8994-codec", |
141 | .ops = &smdk_ops, | 142 | .ops = &smdk_ops, |
142 | }, | 143 | }, |
@@ -153,9 +154,25 @@ static struct snd_soc_card smdk = { | |||
153 | static int smdk_audio_probe(struct platform_device *pdev) | 154 | static int smdk_audio_probe(struct platform_device *pdev) |
154 | { | 155 | { |
155 | int ret; | 156 | int ret; |
157 | struct device_node *np = pdev->dev.of_node; | ||
156 | struct snd_soc_card *card = &smdk; | 158 | struct snd_soc_card *card = &smdk; |
157 | 159 | ||
158 | card->dev = &pdev->dev; | 160 | card->dev = &pdev->dev; |
161 | |||
162 | if (np) { | ||
163 | smdk_dai[0].cpu_dai_name = NULL; | ||
164 | smdk_dai[0].cpu_of_node = of_parse_phandle(np, | ||
165 | "samsung,i2s-controller", 0); | ||
166 | if (!smdk_dai[0].cpu_of_node) { | ||
167 | dev_err(&pdev->dev, | ||
168 | "Property 'samsung,i2s-controller' missing or invalid\n"); | ||
169 | ret = -EINVAL; | ||
170 | } | ||
171 | |||
172 | smdk_dai[0].platform_name = NULL; | ||
173 | smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node; | ||
174 | } | ||
175 | |||
159 | ret = snd_soc_register_card(card); | 176 | ret = snd_soc_register_card(card); |
160 | 177 | ||
161 | if (ret) | 178 | if (ret) |
@@ -173,10 +190,19 @@ static int smdk_audio_remove(struct platform_device *pdev) | |||
173 | return 0; | 190 | return 0; |
174 | } | 191 | } |
175 | 192 | ||
193 | #ifdef CONFIG_OF | ||
194 | static const struct of_device_id samsung_wm8994_of_match[] = { | ||
195 | { .compatible = "samsung,smdk-wm8994", }, | ||
196 | {}, | ||
197 | }; | ||
198 | MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); | ||
199 | #endif /* CONFIG_OF */ | ||
200 | |||
176 | static struct platform_driver smdk_audio_driver = { | 201 | static struct platform_driver smdk_audio_driver = { |
177 | .driver = { | 202 | .driver = { |
178 | .name = "smdk-audio", | 203 | .name = "smdk-audio", |
179 | .owner = THIS_MODULE, | 204 | .owner = THIS_MODULE, |
205 | .of_match_table = of_match_ptr(samsung_wm8994_of_match), | ||
180 | }, | 206 | }, |
181 | .probe = smdk_audio_probe, | 207 | .probe = smdk_audio_probe, |
182 | .remove = smdk_audio_remove, | 208 | .remove = smdk_audio_remove, |