175-avila_hss_audio_support.patch 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090
  1. --- a/sound/soc/Kconfig
  2. +++ b/sound/soc/Kconfig
  3. @@ -57,6 +57,7 @@ source "sound/soc/tegra/Kconfig"
  4. source "sound/soc/txx9/Kconfig"
  5. source "sound/soc/ux500/Kconfig"
  6. source "sound/soc/xtensa/Kconfig"
  7. +source "sound/soc/gw-avila/Kconfig"
  8. # Supported codecs
  9. source "sound/soc/codecs/Kconfig"
  10. --- a/sound/soc/Makefile
  11. +++ b/sound/soc/Makefile
  12. @@ -38,3 +38,4 @@ obj-$(CONFIG_SND_SOC) += tegra/
  13. obj-$(CONFIG_SND_SOC) += txx9/
  14. obj-$(CONFIG_SND_SOC) += ux500/
  15. obj-$(CONFIG_SND_SOC) += xtensa/
  16. +obj-$(CONFIG_SND_SOC) += gw-avila/
  17. --- /dev/null
  18. +++ b/sound/soc/gw-avila/Kconfig
  19. @@ -0,0 +1,17 @@
  20. +config SND_GW_AVILA_SOC_PCM
  21. + tristate
  22. +
  23. +config SND_GW_AVILA_SOC_HSS
  24. + tristate
  25. +
  26. +config SND_GW_AVILA_SOC
  27. + tristate "SoC Audio for the Gateworks AVILA Family"
  28. + depends on ARCH_IXP4XX && SND_SOC
  29. + select SND_GW_AVILA_SOC_PCM
  30. + select SND_GW_AVILA_SOC_HSS
  31. + select SND_SOC_TLV320AIC3X
  32. + help
  33. + Say Y or M if you want to add support for codecs attached to
  34. + the Gateworks HSS interface. You will also need
  35. + to select the audio interfaces to support below.
  36. +
  37. --- /dev/null
  38. +++ b/sound/soc/gw-avila/Makefile
  39. @@ -0,0 +1,8 @@
  40. +# Gateworks Avila HSS Platform Support
  41. +snd-soc-gw-avila-objs := gw-avila.o ixp4xx_hss.o
  42. +snd-soc-gw-avila-pcm-objs := gw-avila-pcm.o
  43. +snd-soc-gw-avila-hss-objs := gw-avila-hss.o
  44. +
  45. +obj-$(CONFIG_SND_GW_AVILA_SOC) += snd-soc-gw-avila.o
  46. +obj-$(CONFIG_SND_GW_AVILA_SOC_PCM) += snd-soc-gw-avila-pcm.o
  47. +obj-$(CONFIG_SND_GW_AVILA_SOC_HSS) += snd-soc-gw-avila-hss.o
  48. --- /dev/null
  49. +++ b/sound/soc/gw-avila/gw-avila-hss.c
  50. @@ -0,0 +1,103 @@
  51. +/*
  52. + * gw-avila-hss.c -- HSS Audio Support for Gateworks Avila
  53. + *
  54. + * Author: Chris Lang <clang@gateworks.com>
  55. + *
  56. + * This program is free software; you can redistribute it and/or modify
  57. + * it under the terms of the GNU General Public License version 2 as
  58. + * published by the Free Software Foundation.
  59. + */
  60. +
  61. +#include <linux/init.h>
  62. +#include <linux/module.h>
  63. +#include <linux/platform_device.h>
  64. +#include <linux/interrupt.h>
  65. +#include <linux/wait.h>
  66. +#include <linux/delay.h>
  67. +
  68. +#include <sound/core.h>
  69. +#include <sound/pcm.h>
  70. +#include <sound/ac97_codec.h>
  71. +#include <sound/initval.h>
  72. +#include <sound/soc.h>
  73. +
  74. +#include <asm/irq.h>
  75. +#include <linux/mutex.h>
  76. +#include <linux/gpio.h>
  77. +
  78. +#include "ixp4xx_hss.h"
  79. +#include "gw-avila-hss.h"
  80. +
  81. +#define gw_avila_hss_suspend NULL
  82. +#define gw_avila_hss_resume NULL
  83. +
  84. +struct snd_soc_dai_driver gw_avila_hss_dai = {
  85. + .playback = {
  86. + .channels_min = 2,
  87. + .channels_max = 2,
  88. + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  89. + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
  90. + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
  91. + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
  92. + SNDRV_PCM_RATE_KNOT),
  93. + .formats = SNDRV_PCM_FMTBIT_S16_LE, },
  94. + .capture = {
  95. + .channels_min = 2,
  96. + .channels_max = 2,
  97. + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  98. + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
  99. + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
  100. + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
  101. + SNDRV_PCM_RATE_KNOT),
  102. + .formats = SNDRV_PCM_FMTBIT_S16_LE, },
  103. +};
  104. +
  105. +static const struct snd_soc_component_driver gw_avila_hss_component = {
  106. + .name = "gw_avila_hss",
  107. +};
  108. +
  109. +static int gw_avila_hss_probe(struct platform_device *pdev)
  110. +{
  111. + int port = (pdev->id < 2) ? 0 : 1;
  112. + int channel = (pdev->id % 2);
  113. +
  114. + hss_handle[pdev->id] = hss_init(port, channel);
  115. + if (!hss_handle[pdev->id]) {
  116. + return -ENODEV;
  117. + }
  118. +
  119. + return snd_soc_register_component(&pdev->dev, &gw_avila_hss_component,
  120. + &gw_avila_hss_dai, 1);
  121. +}
  122. +
  123. +static int gw_avila_hss_remove(struct platform_device *pdev)
  124. +{
  125. + snd_soc_unregister_component(&pdev->dev);
  126. +
  127. + return 0;
  128. +}
  129. +
  130. +static struct platform_driver gw_avila_hss_driver = {
  131. + .probe = gw_avila_hss_probe,
  132. + .remove = gw_avila_hss_remove,
  133. + .driver = {
  134. + .name = "gw_avila_hss",
  135. + .owner = THIS_MODULE,
  136. + }
  137. +};
  138. +
  139. +static int __init gw_avila_hss_init(void)
  140. +{
  141. + return platform_driver_register(&gw_avila_hss_driver);
  142. +}
  143. +module_init(gw_avila_hss_init);
  144. +
  145. +static void __exit gw_avila_hss_exit(void)
  146. +{
  147. + platform_driver_unregister(&gw_avila_hss_driver);
  148. +}
  149. +module_exit(gw_avila_hss_exit);
  150. +
  151. +MODULE_AUTHOR("Chris Lang");
  152. +MODULE_DESCRIPTION("HSS Audio Driver for Gateworks Avila");
  153. +MODULE_LICENSE("GPL");
  154. --- /dev/null
  155. +++ b/sound/soc/gw-avila/gw-avila-hss.h
  156. @@ -0,0 +1,12 @@
  157. +/*
  158. + * Author: Chris Lang <clang@gateworks.com>
  159. + *
  160. + * This program is free software; you can redistribute it and/or modify
  161. + * it under the terms of the GNU General Public License version 2 as
  162. + * published by the Free Software Foundation.
  163. + */
  164. +
  165. +#ifndef _GW_AVILA_HSS_H
  166. +#define _GW_AVILA_HSS_H
  167. +
  168. +#endif
  169. --- /dev/null
  170. +++ b/sound/soc/gw-avila/gw-avila-pcm.c
  171. @@ -0,0 +1,327 @@
  172. +/*
  173. + * ALSA PCM interface for the TI DAVINCI processor
  174. + *
  175. + * Author: Chris Lang, <clang@gateworks.com>
  176. + * Copyright: (C) 2009 Gateworks Corporation
  177. + *
  178. + * Based On: davinci-evm.c, Author: Vladimir Barinov, <vbarinov@ru.mvista.com>
  179. + *
  180. + * This program is free software; you can redistribute it and/or modify
  181. + * it under the terms of the GNU General Public License version 2 as
  182. + * published by the Free Software Foundation.
  183. + */
  184. +
  185. +#include <linux/module.h>
  186. +#include <linux/init.h>
  187. +#include <linux/platform_device.h>
  188. +#include <linux/slab.h>
  189. +#include <linux/dma-mapping.h>
  190. +
  191. +#include <sound/core.h>
  192. +#include <sound/pcm.h>
  193. +#include <sound/pcm_params.h>
  194. +#include <sound/soc.h>
  195. +
  196. +#include <asm/dma.h>
  197. +
  198. +#include "gw-avila-pcm.h"
  199. +#include "gw-avila-hss.h"
  200. +#include "ixp4xx_hss.h"
  201. +
  202. +#define GW_AVILA_PCM_DEBUG 0
  203. +#if GW_AVILA_PCM_DEBUG
  204. +#define DPRINTK(x...) printk(KERN_DEBUG x)
  205. +#else
  206. +#define DPRINTK(x...)
  207. +#endif
  208. +
  209. +static struct snd_pcm_hardware gw_avila_pcm_hardware = {
  210. + .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
  211. + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
  212. +/* SNDRV_PCM_INFO_PAUSE),*/
  213. + .formats = (SNDRV_PCM_FMTBIT_S16_LE),
  214. + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
  215. + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
  216. + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
  217. + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
  218. + SNDRV_PCM_RATE_KNOT),
  219. + .rate_min = 8000,
  220. + .rate_max = 8000,
  221. + .channels_min = 2,
  222. + .channels_max = 2,
  223. + .buffer_bytes_max = 64 * 1024, // All of the lines below may need to be changed
  224. + .period_bytes_min = 128,
  225. + .period_bytes_max = 4 * 1024,
  226. + .periods_min = 16,
  227. + .periods_max = 32,
  228. + .fifo_size = 0,
  229. +};
  230. +
  231. +struct gw_avila_runtime_data {
  232. + spinlock_t lock;
  233. + int period; /* current DMA period */
  234. + int master_lch; /* Master DMA channel */
  235. + int slave_lch; /* Slave DMA channel */
  236. + struct gw_avila_pcm_dma_params *params; /* DMA params */
  237. +};
  238. +
  239. +static void gw_avila_dma_irq(void *data)
  240. +{
  241. + struct snd_pcm_substream *substream = data;
  242. + snd_pcm_period_elapsed(substream);
  243. +}
  244. +
  245. +static int gw_avila_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  246. +{
  247. + struct snd_pcm_runtime *runtime = substream->runtime;
  248. + struct hss_device *hdev = runtime->private_data;
  249. + int ret = 0;
  250. +
  251. + switch (cmd) {
  252. + case SNDRV_PCM_TRIGGER_START:
  253. + case SNDRV_PCM_TRIGGER_RESUME:
  254. + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  255. + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  256. + hss_tx_start(hdev);
  257. + else
  258. + hss_rx_start(hdev);
  259. + break;
  260. + case SNDRV_PCM_TRIGGER_STOP:
  261. + case SNDRV_PCM_TRIGGER_SUSPEND:
  262. + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  263. + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  264. + hss_tx_stop(hdev);
  265. + else
  266. + hss_rx_stop(hdev);
  267. + break;
  268. + default:
  269. + ret = -EINVAL;
  270. + break;
  271. + }
  272. + return ret;
  273. +}
  274. +
  275. +static int gw_avila_pcm_prepare(struct snd_pcm_substream *substream)
  276. +{
  277. + struct snd_pcm_runtime *runtime = substream->runtime;
  278. + struct hss_device *hdev = runtime->private_data;
  279. +
  280. + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  281. + hss_set_tx_callback(hdev, gw_avila_dma_irq, substream);
  282. + hss_config_tx_dma(hdev, runtime->dma_area, runtime->buffer_size, runtime->period_size);
  283. + } else {
  284. + hss_set_rx_callback(hdev, gw_avila_dma_irq, substream);
  285. + hss_config_rx_dma(hdev, runtime->dma_area, runtime->buffer_size, runtime->period_size);
  286. + }
  287. +
  288. + return 0;
  289. +}
  290. +
  291. +static snd_pcm_uframes_t
  292. +gw_avila_pcm_pointer(struct snd_pcm_substream *substream)
  293. +{
  294. + struct snd_pcm_runtime *runtime = substream->runtime;
  295. + struct hss_device *hdev = runtime->private_data;
  296. +
  297. + unsigned int curr = 0;
  298. + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  299. + curr = hss_curr_offset_tx(hdev);
  300. + else
  301. + curr = hss_curr_offset_rx(hdev);
  302. + return curr;
  303. +}
  304. +
  305. +static int gw_avila_pcm_open(struct snd_pcm_substream *substream)
  306. +{
  307. + struct snd_pcm_runtime *runtime = substream->runtime;
  308. + struct snd_soc_pcm_runtime *rtd = substream->private_data;
  309. + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  310. +
  311. + snd_soc_set_runtime_hwparams(substream, &gw_avila_pcm_hardware);
  312. +
  313. + if (hss_handle[cpu_dai->id] != NULL)
  314. + runtime->private_data = hss_handle[cpu_dai->id];
  315. + else {
  316. + pr_err("hss_handle is NULL\n");
  317. + return -1;
  318. + }
  319. +
  320. + hss_chan_open(hss_handle[cpu_dai->id]);
  321. +
  322. + return 0;
  323. +}
  324. +
  325. +static int gw_avila_pcm_close(struct snd_pcm_substream *substream)
  326. +{
  327. + struct snd_pcm_runtime *runtime = substream->runtime;
  328. + struct hss_device *hdev = runtime->private_data;
  329. +
  330. + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  331. + memset(hdev->tx_buf, 0, runtime->buffer_size);
  332. + } else
  333. + memset(hdev->rx_buf, 0, runtime->buffer_size);
  334. +
  335. + hss_chan_close(hdev);
  336. +
  337. + return 0;
  338. +}
  339. +
  340. +static int gw_avila_pcm_hw_params(struct snd_pcm_substream *substream,
  341. + struct snd_pcm_hw_params *hw_params)
  342. +{
  343. + return snd_pcm_lib_malloc_pages(substream,
  344. + params_buffer_bytes(hw_params));
  345. +}
  346. +
  347. +static int gw_avila_pcm_hw_free(struct snd_pcm_substream *substream)
  348. +{
  349. + struct snd_pcm_runtime *runtime = substream->runtime;
  350. +
  351. + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  352. + memset(runtime->dma_area, 0, runtime->buffer_size);
  353. +
  354. + return snd_pcm_lib_free_pages(substream);
  355. +}
  356. +
  357. +static int gw_avila_pcm_mmap(struct snd_pcm_substream *substream,
  358. + struct vm_area_struct *vma)
  359. +{
  360. + struct snd_pcm_runtime *runtime = substream->runtime;
  361. +
  362. + return dma_mmap_writecombine(substream->pcm->card->dev, vma,
  363. + runtime->dma_area,
  364. + runtime->dma_addr,
  365. + runtime->dma_bytes);
  366. +}
  367. +
  368. +struct snd_pcm_ops gw_avila_pcm_ops = {
  369. + .open = gw_avila_pcm_open,
  370. + .close = gw_avila_pcm_close,
  371. + .ioctl = snd_pcm_lib_ioctl,
  372. + .hw_params = gw_avila_pcm_hw_params,
  373. + .hw_free = gw_avila_pcm_hw_free,
  374. + .prepare = gw_avila_pcm_prepare,
  375. + .trigger = gw_avila_pcm_trigger,
  376. + .pointer = gw_avila_pcm_pointer,
  377. + .mmap = gw_avila_pcm_mmap,
  378. +};
  379. +
  380. +static int gw_avila_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  381. +{
  382. + struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  383. + struct snd_dma_buffer *buf = &substream->dma_buffer;
  384. + size_t size = gw_avila_pcm_hardware.buffer_bytes_max;
  385. +
  386. + buf->dev.type = SNDRV_DMA_TYPE_DEV;
  387. + buf->dev.dev = pcm->card->dev;
  388. + buf->private_data = NULL;
  389. +
  390. + buf->area = dma_alloc_coherent(pcm->card->dev, size,
  391. + &buf->addr, GFP_KERNEL);
  392. +
  393. + if (!buf->area) {
  394. + return -ENOMEM;
  395. + }
  396. +
  397. + memset(buf->area, 0xff, size);
  398. +
  399. + DPRINTK("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
  400. + (void *) buf->area, (void *) buf->addr, size);
  401. +
  402. + buf->bytes = size;
  403. +
  404. + return 0;
  405. +}
  406. +
  407. +static void gw_avila_pcm_free(struct snd_pcm *pcm)
  408. +{
  409. + struct snd_pcm_substream *substream;
  410. + struct snd_dma_buffer *buf;
  411. + int stream;
  412. +
  413. + for (stream = 0; stream < 2; stream++) {
  414. + substream = pcm->streams[stream].substream;
  415. + if (!substream)
  416. + continue;
  417. +
  418. + buf = &substream->dma_buffer;
  419. + if (!buf->area)
  420. + continue;
  421. +
  422. + dma_free_coherent(NULL, buf->bytes, buf->area, 0);
  423. + buf->area = NULL;
  424. + }
  425. +}
  426. +
  427. +static u64 gw_avila_pcm_dmamask = 0xFFFFFFFF;
  428. +
  429. +static int gw_avila_pcm_new(struct snd_soc_pcm_runtime *rtd)
  430. +{
  431. + struct snd_card *card = rtd->card->snd_card;
  432. + struct snd_pcm *pcm = rtd->pcm;
  433. + struct snd_soc_dai *dai = rtd->codec_dai;
  434. + int ret;
  435. +
  436. + if (!card->dev->dma_mask)
  437. + card->dev->dma_mask = &gw_avila_pcm_dmamask;
  438. + if (!card->dev->coherent_dma_mask)
  439. + card->dev->coherent_dma_mask = 0xFFFFFFFF;
  440. +
  441. + if (dai->driver->playback.channels_min) {
  442. + ret = gw_avila_pcm_preallocate_dma_buffer(pcm,
  443. + SNDRV_PCM_STREAM_PLAYBACK);
  444. + if (ret)
  445. + return ret;
  446. + }
  447. +
  448. + if (dai->driver->capture.channels_min) {
  449. + ret = gw_avila_pcm_preallocate_dma_buffer(pcm,
  450. + SNDRV_PCM_STREAM_CAPTURE);
  451. + if (ret)
  452. + return ret;
  453. + }
  454. +
  455. + return 0;
  456. +}
  457. +
  458. +struct snd_soc_platform_driver gw_avila_soc_platform = {
  459. + .ops = &gw_avila_pcm_ops,
  460. + .pcm_new = gw_avila_pcm_new,
  461. + .pcm_free = gw_avila_pcm_free,
  462. +};
  463. +
  464. +static int gw_avila_pcm_platform_probe(struct platform_device *pdev)
  465. +{
  466. + return snd_soc_register_platform(&pdev->dev, &gw_avila_soc_platform);
  467. +}
  468. +
  469. +static int gw_avila_pcm_platform_remove(struct platform_device *pdev)
  470. +{
  471. + snd_soc_unregister_platform(&pdev->dev);
  472. + return 0;
  473. +}
  474. +
  475. +static struct platform_driver gw_avila_pcm_driver = {
  476. + .driver = {
  477. + .name = "gw_avila-audio",
  478. + .owner = THIS_MODULE,
  479. + },
  480. + .probe = gw_avila_pcm_platform_probe,
  481. + .remove = gw_avila_pcm_platform_remove,
  482. +};
  483. +
  484. +static int __init gw_avila_soc_platform_init(void)
  485. +{
  486. + return platform_driver_register(&gw_avila_pcm_driver);
  487. +}
  488. +module_init(gw_avila_soc_platform_init);
  489. +
  490. +static void __exit gw_avila_soc_platform_exit(void)
  491. +{
  492. + platform_driver_unregister(&gw_avila_pcm_driver);
  493. +}
  494. +module_exit(gw_avila_soc_platform_exit);
  495. +
  496. +MODULE_AUTHOR("Chris Lang");
  497. +MODULE_DESCRIPTION("Gateworks Avila PCM DMA module");
  498. +MODULE_LICENSE("GPL");
  499. --- /dev/null
  500. +++ b/sound/soc/gw-avila/gw-avila-pcm.h
  501. @@ -0,0 +1,32 @@
  502. +/*
  503. + * ALSA PCM interface for the Gateworks Avila platform
  504. + *
  505. + * Author: Chris Lang, <clang@gateworks.com>
  506. + * Copyright: (C) 2009 Gateworks Corporation
  507. + *
  508. + * Based On: davinci-evm.c, Author: Vladimir Barinov, <vbarinov@ru.mvista.com>
  509. + *
  510. + * This program is free software; you can redistribute it and/or modify
  511. + * it under the terms of the GNU General Public License version 2 as
  512. + * published by the Free Software Foundation.
  513. + */
  514. +
  515. +#ifndef _GW_AVILA_PCM_H
  516. +#define _GW_AVILA_PCM_H
  517. +
  518. +#if 0
  519. +struct gw_avila_pcm_dma_params {
  520. + char *name; /* stream identifier */
  521. + int channel; /* sync dma channel ID */
  522. + dma_addr_t dma_addr; /* device physical address for DMA */
  523. + unsigned int data_type; /* xfer data type */
  524. +};
  525. +
  526. +struct gw_avila_snd_platform_data {
  527. + int tx_dma_ch; // XXX Do we need this?
  528. + int rx_dma_ch; // XXX Do we need this
  529. +};
  530. +extern struct snd_soc_platform gw_avila_soc_platform[];
  531. +#endif
  532. +
  533. +#endif
  534. --- /dev/null
  535. +++ b/sound/soc/gw-avila/gw-avila.c
  536. @@ -0,0 +1,244 @@
  537. +/*
  538. + * File: sound/soc/gw-avila/gw_avila.c
  539. + * Author: Chris Lang <clang@gateworks.com>
  540. + *
  541. + * Created: Tue June 06 2008
  542. + * Description: Board driver for Gateworks Avila
  543. + *
  544. + * Modified:
  545. + * Copyright 2009 Gateworks Corporation
  546. + *
  547. + * Bugs: What Bugs?
  548. + *
  549. + * This program is free software; you can redistribute it and/or modify
  550. + * it under the terms of the GNU General Public License as published by
  551. + * the Free Software Foundation; either version 2 of the License, or
  552. + * (at your option) any later version.
  553. + *
  554. + * This program is distributed in the hope that it will be useful,
  555. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  556. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  557. + * GNU General Public License for more details.
  558. + *
  559. + * You should have received a copy of the GNU General Public License
  560. + * along with this program; if not, see the file COPYING, or write
  561. + * to the Free Software Foundation, Inc.,
  562. + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  563. + */
  564. +
  565. +#include <linux/module.h>
  566. +#include <linux/moduleparam.h>
  567. +#include <linux/device.h>
  568. +#include <asm/dma.h>
  569. +#include <linux/platform_device.h>
  570. +#include <sound/core.h>
  571. +#include <sound/pcm.h>
  572. +#include <sound/soc.h>
  573. +#include <linux/slab.h>
  574. +#include <linux/gpio.h>
  575. +
  576. +#include "ixp4xx_hss.h"
  577. +#include "gw-avila-hss.h"
  578. +#include "gw-avila-pcm.h"
  579. +
  580. +#define CODEC_FREQ 33333000
  581. +
  582. +static int gw_avila_board_startup(struct snd_pcm_substream *substream)
  583. +{
  584. + pr_debug("%s enter\n", __func__);
  585. + return 0;
  586. +}
  587. +
  588. +static int gw_avila_hw_params(struct snd_pcm_substream *substream,
  589. + struct snd_pcm_hw_params *params)
  590. +{
  591. + struct snd_soc_pcm_runtime *rtd = substream->private_data;
  592. + struct snd_soc_dai *codec_dai = rtd->codec_dai;
  593. + struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  594. +
  595. + int ret = 0;
  596. +
  597. + /* set codec DAI configuration */
  598. + if (cpu_dai->id % 2) {
  599. + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS);
  600. + snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 1, 32);
  601. + } else {
  602. + ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM);
  603. + snd_soc_dai_set_tdm_slot(codec_dai, 0, 0, 0, 32);
  604. + }
  605. +
  606. + if (ret < 0)
  607. + return ret;
  608. +
  609. + /* set the codec system clock */
  610. + ret = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_FREQ, SND_SOC_CLOCK_OUT);
  611. + if (ret < 0)
  612. + return ret;
  613. +
  614. + return 0;
  615. +}
  616. +
  617. +static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
  618. + SND_SOC_DAPM_HP("Headphone Jack", NULL),
  619. + SND_SOC_DAPM_LINE("Line Out", NULL),
  620. + SND_SOC_DAPM_LINE("Line In", NULL),
  621. +};
  622. +
  623. +static const struct snd_soc_dapm_route audio_map[] = {
  624. + {"Headphone Jack", NULL, "HPLOUT"},
  625. + {"Headphone Jack", NULL, "HPROUT"},
  626. +
  627. + /* Line Out connected to LLOUT, RLOUT */
  628. + {"Line Out", NULL, "LLOUT"},
  629. + {"Line Out", NULL, "RLOUT"},
  630. +
  631. + /* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
  632. + {"LINE1L", NULL, "Line In"},
  633. + {"LINE1R", NULL, "Line In"},
  634. +};
  635. +
  636. +/* Logic for a aic3x as connected on a davinci-evm */
  637. +static int avila_aic3x_init(struct snd_soc_pcm_runtime *rtd)
  638. +{
  639. + struct snd_soc_codec *codec = rtd->codec;
  640. + struct snd_soc_dapm_context *dapm = &codec->dapm;
  641. +
  642. + /* Add davinci-evm specific widgets */
  643. + snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
  644. + ARRAY_SIZE(aic3x_dapm_widgets));
  645. +
  646. + /* Set up davinci-evm specific audio path audio_map */
  647. + snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
  648. +
  649. + /* not connected */
  650. + snd_soc_dapm_disable_pin(dapm, "MONO_LOUT");
  651. + //snd_soc_dapm_disable_pin(dapm, "HPLCOM");
  652. + //snd_soc_dapm_disable_pin(dapm, "HPRCOM");
  653. + snd_soc_dapm_disable_pin(dapm, "MIC3L");
  654. + snd_soc_dapm_disable_pin(dapm, "MIC3R");
  655. + snd_soc_dapm_disable_pin(dapm, "LINE2L");
  656. + snd_soc_dapm_disable_pin(dapm, "LINE2R");
  657. +
  658. + /* always connected */
  659. + snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
  660. + snd_soc_dapm_enable_pin(dapm, "Line Out");
  661. + snd_soc_dapm_enable_pin(dapm, "Line In");
  662. +
  663. + snd_soc_dapm_sync(dapm);
  664. +
  665. + return 0;
  666. +}
  667. +
  668. +static struct snd_soc_ops gw_avila_board_ops = {
  669. + .startup = gw_avila_board_startup,
  670. + .hw_params = gw_avila_hw_params,
  671. +};
  672. +
  673. +static struct snd_soc_dai_link gw_avila_board_dai[] = {
  674. + {
  675. + .name = "HSS-0",
  676. + .stream_name = "HSS-0",
  677. + .cpu_dai_name = "gw_avila_hss.0",
  678. + .codec_dai_name = "tlv320aic3x-hifi",
  679. + .codec_name = "tlv320aic3x-codec.0-001b",
  680. + .platform_name = "gw_avila-audio.0",
  681. + .init = avila_aic3x_init,
  682. + .ops = &gw_avila_board_ops,
  683. + },{
  684. + .name = "HSS-1",
  685. + .stream_name = "HSS-1",
  686. + .cpu_dai_name = "gw_avila_hss.1",
  687. + .codec_dai_name = "tlv320aic3x-hifi",
  688. + .codec_name = "tlv320aic3x-codec.0-001a",
  689. + .platform_name = "gw_avila-audio.1",
  690. + .init = avila_aic3x_init,
  691. + .ops = &gw_avila_board_ops,
  692. + },{
  693. + .name = "HSS-2",
  694. + .stream_name = "HSS-2",
  695. + .cpu_dai_name = "gw_avila_hss.2",
  696. + .codec_dai_name = "tlv320aic3x-hifi",
  697. + .codec_name = "tlv320aic3x-codec.0-0019",
  698. + .platform_name = "gw_avila-audio.2",
  699. + .init = avila_aic3x_init,
  700. + .ops = &gw_avila_board_ops,
  701. + },{
  702. + .name = "HSS-3",
  703. + .stream_name = "HSS-3",
  704. + .cpu_dai_name = "gw_avila_hss.3",
  705. + .codec_dai_name = "tlv320aic3x-hifi",
  706. + .codec_name = "tlv320aic3x-codec.0-0018",
  707. + .platform_name = "gw_avila-audio.3",
  708. + .init = avila_aic3x_init,
  709. + .ops = &gw_avila_board_ops,
  710. + },
  711. +};
  712. +
  713. +static struct snd_soc_card gw_avila_board[] = {
  714. + {
  715. + .name = "gw_avila-board.0",
  716. + .owner = THIS_MODULE,
  717. + .dai_link = &gw_avila_board_dai[0],
  718. + .num_links = 1,
  719. + },{
  720. + .name = "gw_avila-board.1",
  721. + .owner = THIS_MODULE,
  722. + .dai_link = &gw_avila_board_dai[1],
  723. + .num_links = 1,
  724. + },{
  725. + .name = "gw_avila-board.2",
  726. + .owner = THIS_MODULE,
  727. + .dai_link = &gw_avila_board_dai[2],
  728. + .num_links = 1,
  729. + },{
  730. + .name = "gw_avila-board.3",
  731. + .owner = THIS_MODULE,
  732. + .dai_link = &gw_avila_board_dai[3],
  733. + .num_links = 1,
  734. + }
  735. +};
  736. +
  737. +static struct platform_device *gw_avila_board_snd_device[4];
  738. +
  739. +static int __init gw_avila_board_init(void)
  740. +{
  741. + int ret;
  742. + struct port *port;
  743. + int i;
  744. +
  745. + if ((hss_port[0] = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL)
  746. + return -ENOMEM;
  747. +
  748. + if ((hss_port[1] = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL)
  749. + return -ENOMEM;
  750. +
  751. + for (i = 0; i < 4; i++) {
  752. + gw_avila_board_snd_device[i] = platform_device_alloc("soc-audio", i);
  753. + if (!gw_avila_board_snd_device[i]) {
  754. + return -ENOMEM;
  755. + }
  756. +
  757. + platform_set_drvdata(gw_avila_board_snd_device[i], &gw_avila_board[i]);
  758. + ret = platform_device_add(gw_avila_board_snd_device[i]);
  759. +
  760. + if (ret) {
  761. + platform_device_put(gw_avila_board_snd_device[i]);
  762. + }
  763. + }
  764. + return ret;
  765. +}
  766. +
  767. +static void __exit gw_avila_board_exit(void)
  768. +{
  769. + int i;
  770. + for (i = 0; i < 4; i++)
  771. + platform_device_unregister(gw_avila_board_snd_device[i]);
  772. +}
  773. +
  774. +module_init(gw_avila_board_init);
  775. +module_exit(gw_avila_board_exit);
  776. +
  777. +/* Module information */
  778. +MODULE_AUTHOR("Chris Lang");
  779. +MODULE_DESCRIPTION("ALSA SoC HSS Audio gw_avila board");
  780. +MODULE_LICENSE("GPL");
  781. --- /dev/null
  782. +++ b/sound/soc/gw-avila/ixp4xx_hss.c
  783. @@ -0,0 +1,902 @@
  784. +/*
  785. + * Intel IXP4xx HSS (synchronous serial port) driver for Linux
  786. + *
  787. + * Copyright (C) 2009 Chris Lang <clang@gateworks.com>
  788. + *
  789. + * This program is free software; you can redistribute it and/or modify it
  790. + * under the terms of version 2 of the GNU General Public License
  791. + * as published by the Free Software Foundation.
  792. + */
  793. +
  794. +#include <linux/module.h>
  795. +#include <linux/bitops.h>
  796. +#include <linux/cdev.h>
  797. +#include <linux/dma-mapping.h>
  798. +#include <linux/dmapool.h>
  799. +#include <linux/fs.h>
  800. +#include <linux/io.h>
  801. +#include <linux/kernel.h>
  802. +#include <linux/platform_device.h>
  803. +#include <linux/poll.h>
  804. +#include <linux/slab.h>
  805. +#include <linux/delay.h>
  806. +
  807. +#include <mach/npe.h>
  808. +#include <mach/qmgr.h>
  809. +
  810. +#include "ixp4xx_hss.h"
  811. +
  812. +/*****************************************************************************
  813. + * global variables
  814. + ****************************************************************************/
  815. +
  816. +void hss_chan_read(unsigned long data);
  817. +static char lock_init = 0;
  818. +static spinlock_t npe_lock;
  819. +static struct npe *npe;
  820. +
  821. +static const struct {
  822. + int tx, txdone, rx, rxfree, chan;
  823. +}queue_ids[2] = {{HSS0_PKT_TX0_QUEUE, HSS0_PKT_TXDONE_QUEUE, HSS0_PKT_RX_QUEUE,
  824. + HSS0_PKT_RXFREE0_QUEUE, HSS0_CHL_RXTRIG_QUEUE},
  825. + {HSS1_PKT_TX0_QUEUE, HSS1_PKT_TXDONE_QUEUE, HSS1_PKT_RX_QUEUE,
  826. + HSS1_PKT_RXFREE0_QUEUE, HSS1_CHL_RXTRIG_QUEUE},
  827. +};
  828. +
  829. +struct port *hss_port[2];
  830. +struct hss_device *hss_handle[32];
  831. +EXPORT_SYMBOL(hss_handle);
  832. +
  833. +/*****************************************************************************
  834. + * utility functions
  835. + ****************************************************************************/
  836. +
  837. +#ifndef __ARMEB__
  838. +static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
  839. +{
  840. + int i;
  841. + for (i = 0; i < cnt; i++)
  842. + dest[i] = swab32(src[i]);
  843. +}
  844. +#endif
  845. +
  846. +static inline unsigned int sub_offset(unsigned int a, unsigned int b,
  847. + unsigned int modulo)
  848. +{
  849. + return (modulo /* make sure the result >= 0 */ + a - b) % modulo;
  850. +}
  851. +
  852. +/*****************************************************************************
  853. + * HSS access
  854. + ****************************************************************************/
  855. +
  856. +static void hss_config_load(struct port *port)
  857. +{
  858. + struct msg msg;
  859. +
  860. + do {
  861. + memset(&msg, 0, sizeof(msg));
  862. + msg.cmd = PORT_CONFIG_LOAD;
  863. + msg.hss_port = port->id;
  864. + if (npe_send_message(npe, &msg, "HSS_LOAD_CONFIG"))
  865. + break;
  866. + if (npe_recv_message(npe, &msg, "HSS_LOAD_CONFIG"))
  867. + break;
  868. +
  869. + /* HSS_LOAD_CONFIG for port #1 returns port_id = #4 */
  870. + if (msg.cmd != PORT_CONFIG_LOAD || msg.data32)
  871. + break;
  872. +
  873. + /* HDLC may stop working without this */
  874. + npe_recv_message(npe, &msg, "FLUSH_IT");
  875. + return;
  876. + } while (0);
  877. +
  878. + printk(KERN_CRIT "HSS-%i: unable to reload HSS configuration\n",
  879. + port->id);
  880. + BUG();
  881. +}
  882. +
  883. +static void hss_config_set_pcr(struct port *port)
  884. +{
  885. + struct msg msg;
  886. +
  887. + do {
  888. + memset(&msg, 0, sizeof(msg));
  889. + msg.cmd = PORT_CONFIG_WRITE;
  890. + msg.hss_port = port->id;
  891. + msg.index = HSS_CONFIG_TX_PCR;
  892. +#if 0
  893. + msg.data32 = PCR_FRM_SYNC_RISINGEDGE | PCR_MSB_ENDIAN |
  894. + PCR_TX_DATA_ENABLE | PCR_TX_UNASS_HIGH_IMP | PCR_TX_V56K_HIGH_IMP | PCR_TX_FB_HIGH_IMP;
  895. +#else
  896. + msg.data32 = PCR_FRM_SYNC_RISINGEDGE | PCR_MSB_ENDIAN |
  897. + PCR_TX_DATA_ENABLE | PCR_TX_FB_HIGH_IMP | PCR_DCLK_EDGE_RISING;
  898. +#endif
  899. + if (port->frame_size % 8 == 0)
  900. + msg.data32 |= PCR_SOF_NO_FBIT;
  901. +
  902. + if (npe_send_message(npe, &msg, "HSS_SET_TX_PCR"))
  903. + break;
  904. +
  905. + msg.index = HSS_CONFIG_RX_PCR;
  906. + msg.data32 &= ~ (PCR_DCLK_EDGE_RISING | PCR_FCLK_EDGE_RISING | PCR_TX_DATA_ENABLE);
  907. +
  908. + if (npe_send_message(npe, &msg, "HSS_SET_RX_PCR"))
  909. + break;
  910. + return;
  911. + } while (0);
  912. +
  913. + printk(KERN_CRIT "HSS-%i: unable to set HSS PCR registers\n", port->id);
  914. + BUG();
  915. +}
  916. +
  917. +static void hss_config_set_core(struct port *port)
  918. +{
  919. + struct msg msg;
  920. +
  921. + memset(&msg, 0, sizeof(msg));
  922. + msg.cmd = PORT_CONFIG_WRITE;
  923. + msg.hss_port = port->id;
  924. + msg.index = HSS_CONFIG_CORE_CR;
  925. +#if 0
  926. + msg.data32 = 0 | CCR_LOOPBACK |
  927. + (port->id ? CCR_SECOND_HSS : 0);
  928. +#else
  929. + msg.data32 = 0 |
  930. + (port->id ? CCR_SECOND_HSS : 0);
  931. +#endif
  932. + if (npe_send_message(npe, &msg, "HSS_SET_CORE_CR")) {
  933. + printk(KERN_CRIT "HSS-%i: unable to set HSS core control"
  934. + " register\n", port->id);
  935. + BUG();
  936. + }
  937. +}
  938. +
  939. +static void hss_config_set_line(struct port *port)
  940. +{
  941. + struct msg msg;
  942. +
  943. + hss_config_set_pcr(port);
  944. + hss_config_set_core(port);
  945. +
  946. + memset(&msg, 0, sizeof(msg));
  947. + msg.cmd = PORT_CONFIG_WRITE;
  948. + msg.hss_port = port->id;
  949. + msg.index = HSS_CONFIG_CLOCK_CR;
  950. + msg.data32 = CLK42X_SPEED_8192KHZ /* FIXME */;
  951. + if (npe_send_message(npe, &msg, "HSS_SET_CLOCK_CR")) {
  952. + printk(KERN_CRIT "HSS-%i: unable to set HSS clock control"
  953. + " register\n", port->id);
  954. + BUG();
  955. + }
  956. +}
  957. +
  958. +static void hss_config_set_rx_frame(struct port *port)
  959. +{
  960. + struct msg msg;
  961. +
  962. + memset(&msg, 0, sizeof(msg));
  963. + msg.cmd = PORT_CONFIG_WRITE;
  964. + msg.hss_port = port->id;
  965. + msg.index = HSS_CONFIG_RX_FCR;
  966. + msg.data16a = port->frame_sync_offset;
  967. + msg.data16b = port->frame_size - 1;
  968. + if (npe_send_message(npe, &msg, "HSS_SET_RX_FCR")) {
  969. + printk(KERN_CRIT "HSS-%i: unable to set HSS RX frame size"
  970. + " and offset\n", port->id);
  971. + BUG();
  972. + }
  973. +}
  974. +
  975. +static void hss_config_set_frame(struct port *port)
  976. +{
  977. + struct msg msg;
  978. +
  979. + memset(&msg, 0, sizeof(msg));
  980. + msg.cmd = PORT_CONFIG_WRITE;
  981. + msg.hss_port = port->id;
  982. + msg.index = HSS_CONFIG_TX_FCR;
  983. + msg.data16a = TX_FRAME_SYNC_OFFSET;
  984. + msg.data16b = port->frame_size - 1;
  985. + if (npe_send_message(npe, &msg, "HSS_SET_TX_FCR")) {
  986. + printk(KERN_CRIT "HSS-%i: unable to set HSS TX frame size"
  987. + " and offset\n", port->id);
  988. + BUG();
  989. + }
  990. + hss_config_set_rx_frame(port);
  991. +}
  992. +
  993. +static void hss_config_set_lut(struct port *port)
  994. +{
  995. + struct msg msg;
  996. + int chan_count = 32;
  997. +
  998. + memset(&msg, 0, sizeof(msg));
  999. + msg.cmd = PORT_CONFIG_WRITE;
  1000. + msg.hss_port = port->id;
  1001. +
  1002. + msg.index = HSS_CONFIG_TX_LUT;
  1003. + msg.data32 = 0xffffffff;
  1004. + npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
  1005. + msg.index += 4;
  1006. + npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
  1007. + msg.data32 = 0x0;
  1008. + msg.index += 4;
  1009. + npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
  1010. + msg.index += 4;
  1011. + npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
  1012. + msg.index += 4;
  1013. + npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
  1014. + msg.index += 4;
  1015. + npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
  1016. + msg.index += 4;
  1017. + npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
  1018. + msg.index += 4;
  1019. + npe_send_message(npe, &msg, "HSS_SET_TX_LUT");
  1020. +
  1021. + msg.index = HSS_CONFIG_RX_LUT;
  1022. + msg.data32 = 0xffffffff;
  1023. + npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
  1024. + msg.index += 4;
  1025. + npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
  1026. + msg.data32 = 0x0;
  1027. + msg.index += 4;
  1028. + npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
  1029. + msg.index += 4;
  1030. + npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
  1031. + msg.index += 4;
  1032. + npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
  1033. + msg.index += 4;
  1034. + npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
  1035. + msg.index += 4;
  1036. + npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
  1037. + msg.index += 4;
  1038. + npe_send_message(npe, &msg, "HSS_SET_RX_LUT");
  1039. +
  1040. + hss_config_set_frame(port);
  1041. +
  1042. + memset(&msg, 0, sizeof(msg));
  1043. + msg.cmd = CHAN_NUM_CHANS_WRITE;
  1044. + msg.hss_port = port->id;
  1045. + msg.data8a = chan_count;
  1046. + if (npe_send_message(npe, &msg, "CHAN_NUM_CHANS_WRITE")) {
  1047. + printk(KERN_CRIT "HSS-%i: unable to set HSS channel count\n",
  1048. + port->id);
  1049. + BUG();
  1050. + }
  1051. +}
  1052. +
  1053. +static u32 hss_config_get_status(struct port *port)
  1054. +{
  1055. + struct msg msg;
  1056. +
  1057. + do {
  1058. + memset(&msg, 0, sizeof(msg));
  1059. + msg.cmd = PORT_ERROR_READ;
  1060. + msg.hss_port = port->id;
  1061. + if (npe_send_message(npe, &msg, "PORT_ERROR_READ"))
  1062. + break;
  1063. + if (npe_recv_message(npe, &msg, "PORT_ERROR_READ"))
  1064. + break;
  1065. +
  1066. + return msg.data32;
  1067. + } while (0);
  1068. +
  1069. + printk(KERN_CRIT "HSS-%i: unable to read HSS status\n", port->id);
  1070. + BUG();
  1071. +}
  1072. +
  1073. +static void hss_config_start_chan(struct port *port)
  1074. +{
  1075. + struct msg msg;
  1076. +
  1077. + port->chan_last_tx = 0;
  1078. + port->chan_last_rx = 0;
  1079. +
  1080. + do {
  1081. + memset(&msg, 0, sizeof(msg));
  1082. + msg.cmd = CHAN_RX_BUF_ADDR_WRITE;
  1083. + msg.hss_port = port->id;
  1084. + msg.data32 = port->chan_rx_buf_phys;
  1085. + if (npe_send_message(npe, &msg, "CHAN_RX_BUF_ADDR_WRITE"))
  1086. + break;
  1087. +
  1088. + memset(&msg, 0, sizeof(msg));
  1089. + msg.cmd = CHAN_TX_BUF_ADDR_WRITE;
  1090. + msg.hss_port = port->id;
  1091. + msg.data32 = port->chan_tx_pointers_phys;
  1092. + if (npe_send_message(npe, &msg, "CHAN_TX_BUF_ADDR_WRITE"))
  1093. + break;
  1094. +
  1095. + memset(&msg, 0, sizeof(msg));
  1096. + msg.cmd = CHAN_FLOW_ENABLE;
  1097. + msg.hss_port = port->id;
  1098. + if (npe_send_message(npe, &msg, "CHAN_FLOW_ENABLE"))
  1099. + break;
  1100. + port->chan_started = 1;
  1101. + return;
  1102. + } while (0);
  1103. +
  1104. + printk(KERN_CRIT "HSS-%i: unable to start channelized flow\n",
  1105. + port->id);
  1106. + BUG();
  1107. +}
  1108. +
  1109. +static void hss_config_stop_chan(struct port *port)
  1110. +{
  1111. + struct msg msg;
  1112. +
  1113. + if (!port->chan_started)
  1114. + return;
  1115. +
  1116. + memset(&msg, 0, sizeof(msg));
  1117. + msg.cmd = CHAN_FLOW_DISABLE;
  1118. + msg.hss_port = port->id;
  1119. + if (npe_send_message(npe, &msg, "CHAN_FLOW_DISABLE")) {
  1120. + printk(KERN_CRIT "HSS-%i: unable to stop channelized flow\n",
  1121. + port->id);
  1122. + BUG();
  1123. + }
  1124. + hss_config_get_status(port); /* make sure it's halted */
  1125. + port->chan_started = 0;
  1126. +}
  1127. +
  1128. +static int hss_config_load_firmware(struct port *port)
  1129. +{
  1130. + struct msg msg;
  1131. +
  1132. + if (port->initialized)
  1133. + return 0;
  1134. +
  1135. + if (!npe_running(npe)) {
  1136. + int err;
  1137. + if ((err = npe_load_firmware(npe, "NPE-A-HSS",
  1138. + port->dev)))
  1139. + return err;
  1140. + }
  1141. +
  1142. + do {
  1143. + /* HSS main configuration */
  1144. + hss_config_set_line(port);
  1145. +
  1146. + hss_config_set_frame(port);
  1147. +
  1148. + /* Channelized operation settings */
  1149. + memset(&msg, 0, sizeof(msg));
  1150. + msg.cmd = CHAN_TX_BLK_CFG_WRITE;
  1151. + msg.hss_port = port->id;
  1152. + msg.data8b = (CHAN_TX_LIST_FRAMES & ~7) / 2;
  1153. + msg.data8a = msg.data8b / 4;
  1154. + msg.data8d = CHAN_TX_LIST_FRAMES - msg.data8b;
  1155. + msg.data8c = msg.data8d / 4;
  1156. + if (npe_send_message(npe, &msg, "CHAN_TX_BLK_CFG_WRITE"))
  1157. + break;
  1158. +
  1159. + memset(&msg, 0, sizeof(msg));
  1160. + msg.cmd = CHAN_RX_BUF_CFG_WRITE;
  1161. + msg.hss_port = port->id;
  1162. + msg.data8a = CHAN_RX_TRIGGER / 8;
  1163. + msg.data8b = CHAN_RX_FRAMES;
  1164. + if (npe_send_message(npe, &msg, "CHAN_RX_BUF_CFG_WRITE"))
  1165. + break;
  1166. +
  1167. + memset(&msg, 0, sizeof(msg));
  1168. + msg.cmd = CHAN_TX_BUF_SIZE_WRITE;
  1169. + msg.hss_port = port->id;
  1170. + msg.data8a = CHAN_TX_LISTS;
  1171. + if (npe_send_message(npe, &msg, "CHAN_TX_BUF_SIZE_WRITE"))
  1172. + break;
  1173. +
  1174. + port->initialized = 1;
  1175. + return 0;
  1176. + } while (0);
  1177. +
  1178. + printk(KERN_CRIT "HSS-%i: unable to start HSS operation\n", port->id);
  1179. + BUG();
  1180. +}
  1181. +
  1182. +void hss_chan_irq(void *pdev)
  1183. +{
  1184. + struct port *port = pdev;
  1185. +
  1186. + qmgr_disable_irq(queue_ids[port->id].chan);
  1187. +
  1188. + tasklet_hi_schedule(&port->task);
  1189. +}
  1190. +
  1191. +
  1192. +int hss_prepare_chan(struct port *port)
  1193. +{
  1194. + int err, i, j;
  1195. + u32 *temp;
  1196. + u32 temp2;
  1197. + u8 *temp3;
  1198. +
  1199. + if (port->initialized)
  1200. + return 0;
  1201. +
  1202. + if ((err = hss_config_load_firmware(port)))
  1203. + return err;
  1204. +
  1205. + if ((err = qmgr_request_queue(queue_ids[port->id].chan,
  1206. + CHAN_QUEUE_LEN, 0, 0, "%s:hss", "hss")))
  1207. + return err;
  1208. +
  1209. + port->chan_tx_buf = dma_alloc_coherent(port->dev, chan_tx_buf_len(port), &port->chan_tx_buf_phys, GFP_DMA);
  1210. + memset(port->chan_tx_buf, 0, chan_tx_buf_len(port));
  1211. +
  1212. + port->chan_tx_pointers = dma_alloc_coherent(port->dev, chan_tx_buf_len(port) / CHAN_TX_LIST_FRAMES * 4, &port->chan_tx_pointers_phys, GFP_DMA);
  1213. +
  1214. + temp3 = port->chan_tx_buf;
  1215. + for (i = 0; i < CHAN_TX_LISTS; i++) {
  1216. + for (j = 0; j < 8; j++) {
  1217. + port->tx_lists[i][j] = temp3;
  1218. + temp3 += CHAN_TX_LIST_FRAMES * 4;
  1219. + }
  1220. + }
  1221. +
  1222. + temp = port->chan_tx_pointers;
  1223. + temp2 = port->chan_tx_buf_phys;
  1224. + for (i = 0; i < CHAN_TX_LISTS; i++)
  1225. + {
  1226. + for (j = 0; j < 32; j++)
  1227. + {
  1228. + *temp = temp2;
  1229. + temp2 += CHAN_TX_LIST_FRAMES;
  1230. + temp++;
  1231. + }
  1232. + }
  1233. +
  1234. + port->chan_rx_buf = dma_alloc_coherent(port->dev, chan_rx_buf_len(port), &port->chan_rx_buf_phys, GFP_DMA);
  1235. +
  1236. + for (i = 0; i < 8; i++) {
  1237. + temp3 = port->chan_rx_buf + (i * 4 * 128);
  1238. + for (j = 0; j < 8; j++) {
  1239. + port->rx_frames[i][j] = temp3;
  1240. + temp3 += CHAN_RX_TRIGGER;
  1241. + }
  1242. + }
  1243. +
  1244. + qmgr_set_irq(queue_ids[port->id].chan, QUEUE_IRQ_SRC_NOT_EMPTY,
  1245. + hss_chan_irq, port);
  1246. +
  1247. + return 0;
  1248. +
  1249. +}
  1250. +
  1251. +int hss_tx_start(struct hss_device *hdev)
  1252. +{
  1253. + unsigned long flags;
  1254. + struct port *port = hdev->port;
  1255. +
  1256. + hdev->tx_loc = 0;
  1257. + hdev->tx_frame = 0;
  1258. +
  1259. + set_bit((1 << hdev->id), &port->chan_tx_bitmap);
  1260. +
  1261. + if (!port->chan_started)
  1262. + {
  1263. + qmgr_enable_irq(queue_ids[port->id].chan);
  1264. + spin_lock_irqsave(&npe_lock, flags);
  1265. + hss_config_start_chan(port);
  1266. + spin_unlock_irqrestore(&npe_lock, flags);
  1267. + hss_chan_irq(port);
  1268. + }
  1269. +
  1270. + return 0;
  1271. +}
  1272. +EXPORT_SYMBOL(hss_tx_start);
  1273. +
  1274. +int hss_rx_start(struct hss_device *hdev)
  1275. +{
  1276. + unsigned long flags;
  1277. + struct port *port = hdev->port;
  1278. +
  1279. + hdev->rx_loc = 0;
  1280. + hdev->rx_frame = 0;
  1281. +
  1282. + set_bit((1 << hdev->id), &port->chan_rx_bitmap);
  1283. +
  1284. + if (!port->chan_started)
  1285. + {
  1286. + qmgr_enable_irq(queue_ids[port->id].chan);
  1287. + spin_lock_irqsave(&npe_lock, flags);
  1288. + hss_config_start_chan(port);
  1289. + spin_unlock_irqrestore(&npe_lock, flags);
  1290. + hss_chan_irq(port);
  1291. + }
  1292. +
  1293. + return 0;
  1294. +}
  1295. +EXPORT_SYMBOL(hss_rx_start);
  1296. +
  1297. +int hss_tx_stop(struct hss_device *hdev)
  1298. +{
  1299. + struct port *port = hdev->port;
  1300. +
  1301. + clear_bit((1 << hdev->id), &port->chan_tx_bitmap);
  1302. +
  1303. + return 0;
  1304. +}
  1305. +EXPORT_SYMBOL(hss_tx_stop);
  1306. +
  1307. +int hss_rx_stop(struct hss_device *hdev)
  1308. +{
  1309. + struct port *port = hdev->port;
  1310. +
  1311. + clear_bit((1 << hdev->id), &port->chan_rx_bitmap);
  1312. +
  1313. + return 0;
  1314. +}
  1315. +EXPORT_SYMBOL(hss_rx_stop);
  1316. +
  1317. +int hss_chan_open(struct hss_device *hdev)
  1318. +{
  1319. + struct port *port = hdev->port;
  1320. + int i, err = 0;
  1321. +
  1322. + if (port->chan_open)
  1323. + return 0;
  1324. +
  1325. + if (port->mode == MODE_HDLC) {
  1326. + err = -ENOSYS;
  1327. + goto out;
  1328. + }
  1329. +
  1330. + if (port->mode == MODE_G704 && port->channels[0] == hdev->id) {
  1331. + err = -EBUSY; /* channel #0 is used for G.704 signaling */
  1332. + goto out;
  1333. + }
  1334. +
  1335. + for (i = MAX_CHANNELS; i > port->frame_size / 8; i--)
  1336. + if (port->channels[i - 1] == hdev->id) {
  1337. + err = -ECHRNG; /* frame too short */
  1338. + goto out;
  1339. + }
  1340. +
  1341. + hdev->rx_loc = hdev->tx_loc = 0;
  1342. + hdev->rx_frame = hdev->tx_frame = 0;
  1343. +
  1344. + //clear_bit((1 << hdev->id), &port->chan_rx_bitmap);
  1345. + //clear_bit((1 << hdev->id), &port->chan_tx_bitmap);
  1346. +
  1347. + if (!port->initialized) {
  1348. + hss_prepare_chan(port);
  1349. +
  1350. + hss_config_stop_chan(port);
  1351. + hdev->open_count++;
  1352. + port->chan_open_count++;
  1353. +
  1354. + hss_config_set_lut(port);
  1355. + hss_config_load(port);
  1356. +
  1357. + }
  1358. + port->chan_open = 1;
  1359. +
  1360. +out:
  1361. + return err;
  1362. +}
  1363. +EXPORT_SYMBOL(hss_chan_open);
  1364. +
  1365. +int hss_chan_close(struct hss_device *hdev)
  1366. +{
  1367. + return 0;
  1368. +}
  1369. +EXPORT_SYMBOL(hss_chan_close);
  1370. +
  1371. +void hss_chan_read(unsigned long data)
  1372. +{
  1373. + struct port *port = (void *)data;
  1374. + struct hss_device *hdev;
  1375. + u8 *hw_buf, *save_buf;
  1376. + u8 *buf;
  1377. + u32 v;
  1378. + unsigned int tx_list, rx_frame;
  1379. + int i, j, channel;
  1380. + u8 more_work = 0;
  1381. +
  1382. +/*
  1383. + My Data in the hardware buffer is scattered by channels into 4 trunks
  1384. + as follows for rx
  1385. +
  1386. + channel 0 channel 1 channel 2 channel 3
  1387. +Trunk 1 = 0 -> 127 128 -> 255 256 -> 383 384 -> 512
  1388. +Trunk 2 = 513 -> 639 640 -> 768 769 -> 895 896 -> 1023
  1389. +Trunk 3 = 1024 -> 1151 1152 -> 1207 1208 -> 1407 1408 -> 1535
  1390. +Trunk 4 = 1535 -> 1663 1664 -> 1791 1792 -> 1920 1921 -> 2047
  1391. +
  1392. + I will get CHAN_RX_TRIGGER worth of bytes out of each channel on each trunk
  1393. + with each IRQ
  1394. +
  1395. + For TX Data, it is split into 8 lists with each list containing 16 bytes per
  1396. + channel
  1397. +
  1398. +Trunk 1 = 0 -> 16 17 -> 32 33 -> 48 49 -> 64
  1399. +Trunk 2 = 65 -> 80 81 -> 96 97 -> 112 113 -> 128
  1400. +Trunk 3 = 129 -> 144 145 -> 160 161 -> 176 177 -> 192
  1401. +Trunk 4 = 193 -> 208 209 -> 224 225 -> 240 241 -> 256
  1402. +
  1403. +*/
  1404. +
  1405. +
  1406. + while ((v = qmgr_get_entry(queue_ids[port->id].chan)))
  1407. + {
  1408. + tx_list = (v >> 8) & 0xFF;
  1409. + rx_frame = v & 0xFF;
  1410. +
  1411. + if (tx_list == 7)
  1412. + tx_list = 0;
  1413. + else
  1414. + tx_list++;
  1415. + for (channel = 0; channel < 8; channel++) {
  1416. +
  1417. + hdev = port->chan_devices[channel];
  1418. + if (!hdev)
  1419. + continue;
  1420. +
  1421. + if (test_bit(1 << channel, &port->chan_tx_bitmap)) {
  1422. + buf = (u8 *)hdev->tx_buf + hdev->tx_loc;
  1423. +#if 0
  1424. + hw_buf = (u8 *)port->chan_tx_buf;
  1425. + hw_buf += (tx_list * CHAN_TX_LIST_FRAMES * 32);
  1426. + hw_buf += (4 * CHAN_TX_LIST_FRAMES * channel);
  1427. + save_buf = hw_buf;
  1428. +#else
  1429. + save_buf = port->tx_lists[tx_list][channel];
  1430. +#endif
  1431. + for (i = 0; i < CHAN_TX_LIST_FRAMES; i++) {
  1432. + hw_buf = save_buf + i;
  1433. + for (j = 0; j < 4; j++) {
  1434. + *hw_buf = *(buf++);
  1435. + hw_buf += CHAN_TX_LIST_FRAMES;
  1436. + }
  1437. +
  1438. + hdev->tx_loc += 4;
  1439. + hdev->tx_frame++;
  1440. + if (hdev->tx_loc >= hdev->tx_buffer_size) {
  1441. + hdev->tx_loc = 0;
  1442. + buf = (u8 *)hdev->tx_buf;
  1443. + }
  1444. + }
  1445. + } else {
  1446. +#if 0
  1447. + hw_buf = (u8 *)port->chan_tx_buf;
  1448. + hw_buf += (tx_list * CHAN_TX_LIST_FRAMES * 32);
  1449. + hw_buf += (4 * CHAN_TX_LIST_FRAMES * channel);
  1450. +#else
  1451. + hw_buf = port->tx_lists[tx_list][channel];
  1452. +#endif
  1453. + memset(hw_buf, 0, 64);
  1454. + }
  1455. +
  1456. + if (hdev->tx_frame >= hdev->tx_period_size && test_bit(1 << channel, &port->chan_tx_bitmap))
  1457. + {
  1458. + hdev->tx_frame %= hdev->tx_period_size;
  1459. + if (hdev->tx_callback)
  1460. + hdev->tx_callback(hdev->tx_data);
  1461. + more_work = 1;
  1462. + }
  1463. +
  1464. + if (test_bit(1 << channel, &port->chan_rx_bitmap)) {
  1465. + buf = (u8 *)hdev->rx_buf + hdev->rx_loc;
  1466. +#if 0
  1467. + hw_buf = (u8 *)port->chan_rx_buf;
  1468. + hw_buf += (4 * CHAN_RX_FRAMES * channel);
  1469. + hw_buf += rx_frame;
  1470. + save_buf = hw_buf;
  1471. +#else
  1472. + save_buf = port->rx_frames[channel][rx_frame >> 4];
  1473. +#endif
  1474. + for (i = 0; i < CHAN_RX_TRIGGER; i++) {
  1475. + hw_buf = save_buf + i;
  1476. + for (j = 0; j < 4; j++) {
  1477. + *(buf++) = *hw_buf;
  1478. + hw_buf += CHAN_RX_FRAMES;
  1479. + }
  1480. + hdev->rx_loc += 4;
  1481. + hdev->rx_frame++;
  1482. + if (hdev->rx_loc >= hdev->rx_buffer_size) {
  1483. + hdev->rx_loc = 0;
  1484. + buf = (u8 *)hdev->rx_buf;
  1485. + }
  1486. + }
  1487. + }
  1488. +
  1489. + if (hdev->rx_frame >= hdev->rx_period_size && test_bit(1 << channel, &port->chan_rx_bitmap))
  1490. + {
  1491. + hdev->rx_frame %= hdev->rx_period_size;
  1492. + if (hdev->rx_callback)
  1493. + hdev->rx_callback(hdev->rx_data);
  1494. + more_work = 1;
  1495. + }
  1496. + }
  1497. +#if 0
  1498. + if (more_work)
  1499. + {
  1500. + tasklet_hi_schedule(&port->task);
  1501. + return;
  1502. + }
  1503. +#endif
  1504. + }
  1505. +
  1506. + qmgr_enable_irq(queue_ids[port->id].chan);
  1507. +
  1508. + return;
  1509. +
  1510. +}
  1511. +
  1512. +struct hss_device *hss_chan_create(struct port *port, unsigned int channel)
  1513. +{
  1514. + struct hss_device *chan_dev;
  1515. + unsigned long flags;
  1516. +
  1517. + chan_dev = kzalloc(sizeof(struct hss_device), GFP_KERNEL);
  1518. +
  1519. + spin_lock_irqsave(&npe_lock, flags);
  1520. +
  1521. + chan_dev->id = channel;
  1522. + chan_dev->port = port;
  1523. +
  1524. + port->channels[channel] = channel;
  1525. +
  1526. + port->chan_devices[channel] = chan_dev;
  1527. +
  1528. + spin_unlock_irqrestore(&npe_lock, flags);
  1529. +
  1530. + return chan_dev;
  1531. +}
  1532. +
  1533. +/*****************************************************************************
  1534. + * initialization
  1535. + ****************************************************************************/
  1536. +
  1537. +static struct platform_device gw_avila_hss_device_0 = {
  1538. + .name = "ixp4xx_hss",
  1539. + .id = 0,
  1540. +};
  1541. +
  1542. +static struct platform_device gw_avila_hss_device_1 = {
  1543. + .name = "ixp4xx_hss",
  1544. + .id = 1,
  1545. +};
  1546. +
  1547. +static struct platform_device *gw_avila_hss_port_0;
  1548. +static struct platform_device *gw_avila_hss_port_1;
  1549. +static u64 hss_dmamask = 0xFFFFFFFF;
  1550. +
  1551. +struct hss_device *hss_init(int id, int channel)
  1552. +{
  1553. + struct port *port = hss_port[id];
  1554. + struct hss_device *hdev;
  1555. + int ret;
  1556. +
  1557. + if (!lock_init)
  1558. + {
  1559. + spin_lock_init(&npe_lock);
  1560. + lock_init = 1;
  1561. + npe = npe_request(0);
  1562. + }
  1563. +
  1564. + if (!port->init) {
  1565. + if (id == 0) {
  1566. + gw_avila_hss_port_0 = platform_device_alloc("hss-port", 0);
  1567. +
  1568. + platform_set_drvdata(gw_avila_hss_port_0, &gw_avila_hss_device_0);
  1569. + port->dev = &gw_avila_hss_port_0->dev;
  1570. +
  1571. + if (!port->dev->dma_mask)
  1572. + port->dev->dma_mask = &hss_dmamask;
  1573. + if (!port->dev->coherent_dma_mask)
  1574. + port->dev->coherent_dma_mask = 0xFFFFFFFF;
  1575. +
  1576. + ret = platform_device_add(gw_avila_hss_port_0);
  1577. +
  1578. + if (ret)
  1579. + platform_device_put(gw_avila_hss_port_0);
  1580. +
  1581. + tasklet_init(&port->task, hss_chan_read, (unsigned long) port);
  1582. + }
  1583. + else
  1584. + {
  1585. + gw_avila_hss_port_1 = platform_device_alloc("hss-port", 1);
  1586. +
  1587. + platform_set_drvdata(gw_avila_hss_port_1, &gw_avila_hss_device_1);
  1588. + port->dev = &gw_avila_hss_port_1->dev;
  1589. +
  1590. + if (!port->dev->dma_mask)
  1591. + port->dev->dma_mask = &hss_dmamask;
  1592. + if (!port->dev->coherent_dma_mask)
  1593. + port->dev->coherent_dma_mask = 0xFFFFFFFF;
  1594. +
  1595. + ret = platform_device_add(gw_avila_hss_port_1);
  1596. +
  1597. + if (ret)
  1598. + platform_device_put(gw_avila_hss_port_1);
  1599. +
  1600. + tasklet_init(&port->task, hss_chan_read, (unsigned long) port);
  1601. + }
  1602. +
  1603. + port->init = 1;
  1604. + port->id = id;
  1605. + port->clock_type = CLOCK_EXT;
  1606. + port->clock_rate = 8192000;
  1607. + port->frame_size = 256; /* E1 */
  1608. + port->mode = MODE_RAW;
  1609. + port->next_rx_frame = 0;
  1610. + memset(port->channels, CHANNEL_UNUSED, sizeof(port->channels));
  1611. + }
  1612. +
  1613. + hdev = hss_chan_create(port, channel);
  1614. +
  1615. + return hdev;
  1616. +}
  1617. +EXPORT_SYMBOL(hss_init);
  1618. +
  1619. +int hss_set_tx_callback(struct hss_device *hdev, void (*tx_callback)(void *), void *tx_data)
  1620. +{
  1621. + BUG_ON(tx_callback == NULL);
  1622. + hdev->tx_callback = tx_callback;
  1623. + hdev->tx_data = tx_data;
  1624. +
  1625. + return 0;
  1626. +}
  1627. +EXPORT_SYMBOL(hss_set_tx_callback);
  1628. +
  1629. +int hss_set_rx_callback(struct hss_device *hdev, void (*rx_callback)(void *), void *rx_data)
  1630. +{
  1631. + BUG_ON(rx_callback == NULL);
  1632. + hdev->rx_callback = rx_callback;
  1633. + hdev->rx_data = rx_data;
  1634. +
  1635. + return 0;
  1636. +}
  1637. +EXPORT_SYMBOL(hss_set_rx_callback);
  1638. +
  1639. +int hss_config_rx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size)
  1640. +{
  1641. + /*
  1642. + * Period Size and Buffer Size are in Frames which are u32
  1643. + * We convert the u32 *buf to u8 in order to make channel reads
  1644. + * and rx_loc easier
  1645. + */
  1646. +
  1647. + hdev->rx_buf = (u8 *)buf;
  1648. + hdev->rx_buffer_size = buffer_size << 2;
  1649. + hdev->rx_period_size = period_size;
  1650. +
  1651. + return 0;
  1652. +}
  1653. +EXPORT_SYMBOL(hss_config_rx_dma);
  1654. +
  1655. +int hss_config_tx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size)
  1656. +{
  1657. + /*
  1658. + * Period Size and Buffer Size are in Frames which are u32
  1659. + * We convert the u32 *buf to u8 in order to make channel reads
  1660. + * and rx_loc easier
  1661. + */
  1662. +
  1663. + hdev->tx_buf = (u8 *)buf;
  1664. + hdev->tx_buffer_size = buffer_size << 2;
  1665. + hdev->tx_period_size = period_size;
  1666. +
  1667. + return 0;
  1668. +}
  1669. +EXPORT_SYMBOL(hss_config_tx_dma);
  1670. +
  1671. +unsigned long hss_curr_offset_rx(struct hss_device *hdev)
  1672. +{
  1673. + return hdev->rx_loc >> 2;
  1674. +}
  1675. +EXPORT_SYMBOL(hss_curr_offset_rx);
  1676. +
  1677. +unsigned long hss_curr_offset_tx(struct hss_device *hdev)
  1678. +{
  1679. + return hdev->tx_loc >> 2;
  1680. +}
  1681. +EXPORT_SYMBOL(hss_curr_offset_tx);
  1682. +
  1683. +MODULE_AUTHOR("Chris Lang");
  1684. +MODULE_DESCRIPTION("Intel IXP4xx HSS Audio driver");
  1685. +MODULE_LICENSE("GPL v2");
  1686. --- /dev/null
  1687. +++ b/sound/soc/gw-avila/ixp4xx_hss.h
  1688. @@ -0,0 +1,401 @@
  1689. +/*
  1690. + *
  1691. + *
  1692. + * Copyright (C) 2009 Gateworks Corporation
  1693. + *
  1694. + * This program is free software; you can redistribute it and/or modify it
  1695. + * under the terms of version 2 of the GNU General Public License
  1696. + * as published by the Free Software Foundation.
  1697. + */
  1698. +
  1699. +#include <linux/types.h>
  1700. +#include <linux/bitops.h>
  1701. +#include <linux/dma-mapping.h>
  1702. +#include <linux/dmapool.h>
  1703. +#include <linux/fs.h>
  1704. +#include <linux/io.h>
  1705. +#include <linux/kernel.h>
  1706. +#include <linux/platform_device.h>
  1707. +#include <linux/poll.h>
  1708. +#include <mach/npe.h>
  1709. +#include <mach/qmgr.h>
  1710. +#include <linux/interrupt.h>
  1711. +
  1712. +//#include <linux/hdlc.h> XXX We aren't HDLC
  1713. +
  1714. +#define DEBUG_QUEUES 0
  1715. +#define DEBUG_DESC 0
  1716. +#define DEBUG_RX 0
  1717. +#define DEBUG_TX 0
  1718. +#define DEBUG_PKT_BYTES 0
  1719. +#define DEBUG_CLOSE 0
  1720. +#define DEBUG_FRAMER 0
  1721. +
  1722. +#define DRV_NAME "ixp4xx_hss"
  1723. +
  1724. +#define PKT_EXTRA_FLAGS 0 /* orig 1 */
  1725. +#define TX_FRAME_SYNC_OFFSET 0 /* channelized */
  1726. +#define PKT_NUM_PIPES 1 /* 1, 2 or 4 */
  1727. +#define PKT_PIPE_FIFO_SIZEW 4 /* total 4 dwords per HSS */
  1728. +
  1729. +#define RX_DESCS 512 /* also length of all RX queues */
  1730. +#define TX_DESCS 512 /* also length of all TX queues */
  1731. +
  1732. +//#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS))
  1733. +#define RX_SIZE (HDLC_MAX_MRU + 4) /* NPE needs more space */
  1734. +#define MAX_CLOSE_WAIT 1000 /* microseconds */
  1735. +#define HSS_COUNT 2
  1736. +#define MIN_FRAME_SIZE 16 /* bits */
  1737. +#define MAX_FRAME_SIZE 257 /* 256 bits + framing bit */
  1738. +#define MAX_CHANNELS (MAX_FRAME_SIZE / 8)
  1739. +#define MAX_CHAN_DEVICES 32
  1740. +#define CHANNEL_HDLC 0xFE
  1741. +#define CHANNEL_UNUSED 0xFF
  1742. +
  1743. +#define NAPI_WEIGHT 16
  1744. +#define CHAN_RX_TRIGGER 16 /* 8 RX frames = 1 ms @ E1 */
  1745. +#define CHAN_RX_FRAMES 128
  1746. +#define CHAN_RX_TRUNKS 1
  1747. +#define MAX_CHAN_RX_BAD_SYNC (CHAN_RX_TRIGGER / 2 /* pairs */ - 3)
  1748. +
  1749. +#define CHAN_TX_LIST_FRAMES CHAN_RX_TRIGGER /* bytes/channel per list, 16 - 48 */
  1750. +#define CHAN_TX_LISTS 8
  1751. +#define CHAN_TX_TRUNKS CHAN_RX_TRUNKS
  1752. +#define CHAN_TX_FRAMES (CHAN_TX_LIST_FRAMES * CHAN_TX_LISTS)
  1753. +
  1754. +#define CHAN_QUEUE_LEN 32 /* minimum possible */
  1755. +
  1756. +#define chan_rx_buf_len(port) (port->frame_size / 8 * CHAN_RX_FRAMES * CHAN_RX_TRUNKS)
  1757. +#define chan_tx_buf_len(port) (port->frame_size / 8 * CHAN_TX_FRAMES * CHAN_TX_TRUNKS)
  1758. +
  1759. +/* Queue IDs */
  1760. +#define HSS0_CHL_RXTRIG_QUEUE 12 /* orig size = 32 dwords */
  1761. +#define HSS0_PKT_RX_QUEUE 13 /* orig size = 32 dwords */
  1762. +#define HSS0_PKT_TX0_QUEUE 14 /* orig size = 16 dwords */
  1763. +#define HSS0_PKT_TX1_QUEUE 15
  1764. +#define HSS0_PKT_TX2_QUEUE 16
  1765. +#define HSS0_PKT_TX3_QUEUE 17
  1766. +#define HSS0_PKT_RXFREE0_QUEUE 18 /* orig size = 16 dwords */
  1767. +#define HSS0_PKT_RXFREE1_QUEUE 19
  1768. +#define HSS0_PKT_RXFREE2_QUEUE 20
  1769. +#define HSS0_PKT_RXFREE3_QUEUE 21
  1770. +#define HSS0_PKT_TXDONE_QUEUE 22 /* orig size = 64 dwords */
  1771. +
  1772. +#define HSS1_CHL_RXTRIG_QUEUE 10
  1773. +#define HSS1_PKT_RX_QUEUE 0
  1774. +#define HSS1_PKT_TX0_QUEUE 5
  1775. +#define HSS1_PKT_TX1_QUEUE 6
  1776. +#define HSS1_PKT_TX2_QUEUE 7
  1777. +#define HSS1_PKT_TX3_QUEUE 8
  1778. +#define HSS1_PKT_RXFREE0_QUEUE 1
  1779. +#define HSS1_PKT_RXFREE1_QUEUE 2
  1780. +#define HSS1_PKT_RXFREE2_QUEUE 3
  1781. +#define HSS1_PKT_RXFREE3_QUEUE 4
  1782. +#define HSS1_PKT_TXDONE_QUEUE 9
  1783. +
  1784. +#define NPE_PKT_MODE_HDLC 0
  1785. +#define NPE_PKT_MODE_RAW 1
  1786. +#define NPE_PKT_MODE_56KMODE 2
  1787. +#define NPE_PKT_MODE_56KENDIAN_MSB 4
  1788. +
  1789. +/* PKT_PIPE_HDLC_CFG_WRITE flags */
  1790. +#define PKT_HDLC_IDLE_ONES 0x1 /* default = flags */
  1791. +#define PKT_HDLC_CRC_32 0x2 /* default = CRC-16 */
  1792. +#define PKT_HDLC_MSB_ENDIAN 0x4 /* default = LE */
  1793. +
  1794. +
  1795. +/* hss_config, PCRs */
  1796. +/* Frame sync sampling, default = active low */
  1797. +#define PCR_FRM_SYNC_ACTIVE_HIGH 0x40000000
  1798. +#define PCR_FRM_SYNC_FALLINGEDGE 0x80000000
  1799. +#define PCR_FRM_SYNC_RISINGEDGE 0xC0000000
  1800. +
  1801. +/* Frame sync pin: input (default) or output generated off a given clk edge */
  1802. +#define PCR_FRM_SYNC_OUTPUT_FALLING 0x20000000
  1803. +#define PCR_FRM_SYNC_OUTPUT_RISING 0x30000000
  1804. +
  1805. +/* Frame and data clock sampling on edge, default = falling */
  1806. +#define PCR_FCLK_EDGE_RISING 0x08000000
  1807. +#define PCR_DCLK_EDGE_RISING 0x04000000
  1808. +
  1809. +/* Clock direction, default = input */
  1810. +#define PCR_SYNC_CLK_DIR_OUTPUT 0x02000000
  1811. +
  1812. +/* Generate/Receive frame pulses, default = enabled */
  1813. +#define PCR_FRM_PULSE_DISABLED 0x01000000
  1814. +
  1815. + /* Data rate is full (default) or half the configured clk speed */
  1816. +#define PCR_HALF_CLK_RATE 0x00200000
  1817. +
  1818. +/* Invert data between NPE and HSS FIFOs? (default = no) */
  1819. +#define PCR_DATA_POLARITY_INVERT 0x00100000
  1820. +
  1821. +/* TX/RX endianness, default = LSB */
  1822. +#define PCR_MSB_ENDIAN 0x00080000
  1823. +
  1824. +/* Normal (default) / open drain mode (TX only) */
  1825. +#define PCR_TX_PINS_OPEN_DRAIN 0x00040000
  1826. +
  1827. +/* No framing bit transmitted and expected on RX? (default = framing bit) */
  1828. +#define PCR_SOF_NO_FBIT 0x00020000
  1829. +
  1830. +/* Drive data pins? */
  1831. +#define PCR_TX_DATA_ENABLE 0x00010000
  1832. +
  1833. +/* Voice 56k type: drive the data pins low (default), high, high Z */
  1834. +#define PCR_TX_V56K_HIGH 0x00002000
  1835. +#define PCR_TX_V56K_HIGH_IMP 0x00004000
  1836. +
  1837. +/* Unassigned type: drive the data pins low (default), high, high Z */
  1838. +#define PCR_TX_UNASS_HIGH 0x00000800
  1839. +#define PCR_TX_UNASS_HIGH_IMP 0x00001000
  1840. +
  1841. +/* T1 @ 1.544MHz only: Fbit dictated in FIFO (default) or high Z */
  1842. +#define PCR_TX_FB_HIGH_IMP 0x00000400
  1843. +
  1844. +/* 56k data endiannes - which bit unused: high (default) or low */
  1845. +#define PCR_TX_56KE_BIT_0_UNUSED 0x00000200
  1846. +
  1847. +/* 56k data transmission type: 32/8 bit data (default) or 56K data */
  1848. +#define PCR_TX_56KS_56K_DATA 0x00000100
  1849. +
  1850. +/* hss_config, cCR */
  1851. +/* Number of packetized clients, default = 1 */
  1852. +#define CCR_NPE_HFIFO_2_HDLC 0x04000000
  1853. +#define CCR_NPE_HFIFO_3_OR_4HDLC 0x08000000
  1854. +
  1855. +/* default = no loopback */
  1856. +#define CCR_LOOPBACK 0x02000000
  1857. +
  1858. +/* HSS number, default = 0 (first) */
  1859. +#define CCR_SECOND_HSS 0x01000000
  1860. +
  1861. +
  1862. +/* hss_config, clkCR: main:10, num:10, denom:12 */
  1863. +#define CLK42X_SPEED_EXP ((0x3FF << 22) | ( 2 << 12) | 15) /*65 KHz*/
  1864. +
  1865. +#define CLK42X_SPEED_512KHZ (( 130 << 22) | ( 2 << 12) | 15)
  1866. +#define CLK42X_SPEED_1536KHZ (( 43 << 22) | ( 18 << 12) | 47)
  1867. +#define CLK42X_SPEED_1544KHZ (( 43 << 22) | ( 33 << 12) | 192)
  1868. +#define CLK42X_SPEED_2048KHZ (( 32 << 22) | ( 34 << 12) | 63)
  1869. +#define CLK42X_SPEED_4096KHZ (( 16 << 22) | ( 34 << 12) | 127)
  1870. +#define CLK42X_SPEED_8192KHZ (( 8 << 22) | ( 34 << 12) | 255)
  1871. +
  1872. +#define CLK46X_SPEED_512KHZ (( 130 << 22) | ( 24 << 12) | 127)
  1873. +#define CLK46X_SPEED_1536KHZ (( 43 << 22) | (152 << 12) | 383)
  1874. +#define CLK46X_SPEED_1544KHZ (( 43 << 22) | ( 66 << 12) | 385)
  1875. +#define CLK46X_SPEED_2048KHZ (( 32 << 22) | (280 << 12) | 511)
  1876. +#define CLK46X_SPEED_4096KHZ (( 16 << 22) | (280 << 12) | 1023)
  1877. +#define CLK46X_SPEED_8192KHZ (( 8 << 22) | (280 << 12) | 2047)
  1878. +
  1879. +
  1880. +/* hss_config, LUT entries */
  1881. +#define TDMMAP_UNASSIGNED 0
  1882. +#define TDMMAP_HDLC 1 /* HDLC - packetized */
  1883. +#define TDMMAP_VOICE56K 2 /* Voice56K - 7-bit channelized */
  1884. +#define TDMMAP_VOICE64K 3 /* Voice64K - 8-bit channelized */
  1885. +
  1886. +/* offsets into HSS config */
  1887. +#define HSS_CONFIG_TX_PCR 0x00 /* port configuration registers */
  1888. +#define HSS_CONFIG_RX_PCR 0x04
  1889. +#define HSS_CONFIG_CORE_CR 0x08 /* loopback control, HSS# */
  1890. +#define HSS_CONFIG_CLOCK_CR 0x0C /* clock generator control */
  1891. +#define HSS_CONFIG_TX_FCR 0x10 /* frame configuration registers */
  1892. +#define HSS_CONFIG_RX_FCR 0x14
  1893. +#define HSS_CONFIG_TX_LUT 0x18 /* channel look-up tables */
  1894. +#define HSS_CONFIG_RX_LUT 0x38
  1895. +
  1896. +
  1897. +/* NPE command codes */
  1898. +/* writes the ConfigWord value to the location specified by offset */
  1899. +#define PORT_CONFIG_WRITE 0x40
  1900. +
  1901. +/* triggers the NPE to load the contents of the configuration table */
  1902. +#define PORT_CONFIG_LOAD 0x41
  1903. +
  1904. +/* triggers the NPE to return an HssErrorReadResponse message */
  1905. +#define PORT_ERROR_READ 0x42
  1906. +
  1907. +/* reset NPE internal status and enable the HssChannelized operation */
  1908. +#define CHAN_FLOW_ENABLE 0x43
  1909. +#define CHAN_FLOW_DISABLE 0x44
  1910. +#define CHAN_IDLE_PATTERN_WRITE 0x45
  1911. +#define CHAN_NUM_CHANS_WRITE 0x46
  1912. +#define CHAN_RX_BUF_ADDR_WRITE 0x47
  1913. +#define CHAN_RX_BUF_CFG_WRITE 0x48
  1914. +#define CHAN_TX_BLK_CFG_WRITE 0x49
  1915. +#define CHAN_TX_BUF_ADDR_WRITE 0x4A
  1916. +#define CHAN_TX_BUF_SIZE_WRITE 0x4B
  1917. +#define CHAN_TSLOTSWITCH_ENABLE 0x4C
  1918. +#define CHAN_TSLOTSWITCH_DISABLE 0x4D
  1919. +
  1920. +/* downloads the gainWord value for a timeslot switching channel associated
  1921. + with bypassNum */
  1922. +#define CHAN_TSLOTSWITCH_GCT_DOWNLOAD 0x4E
  1923. +
  1924. +/* triggers the NPE to reset internal status and enable the HssPacketized
  1925. + operation for the flow specified by pPipe */
  1926. +#define PKT_PIPE_FLOW_ENABLE 0x50
  1927. +#define PKT_PIPE_FLOW_DISABLE 0x51
  1928. +#define PKT_NUM_PIPES_WRITE 0x52
  1929. +#define PKT_PIPE_FIFO_SIZEW_WRITE 0x53
  1930. +#define PKT_PIPE_HDLC_CFG_WRITE 0x54
  1931. +#define PKT_PIPE_IDLE_PATTERN_WRITE 0x55
  1932. +#define PKT_PIPE_RX_SIZE_WRITE 0x56
  1933. +#define PKT_PIPE_MODE_WRITE 0x57
  1934. +
  1935. +/* HDLC packet status values - desc->status */
  1936. +#define ERR_SHUTDOWN 1 /* stop or shutdown occurrance */
  1937. +#define ERR_HDLC_ALIGN 2 /* HDLC alignment error */
  1938. +#define ERR_HDLC_FCS 3 /* HDLC Frame Check Sum error */
  1939. +#define ERR_RXFREE_Q_EMPTY 4 /* RX-free queue became empty while receiving
  1940. + this packet (if buf_len < pkt_len) */
  1941. +#define ERR_HDLC_TOO_LONG 5 /* HDLC frame size too long */
  1942. +#define ERR_HDLC_ABORT 6 /* abort sequence received */
  1943. +#define ERR_DISCONNECTING 7 /* disconnect is in progress */
  1944. +
  1945. +#define CLOCK_EXT 0
  1946. +#define CLOCK_INT 1
  1947. +
  1948. +enum mode {MODE_HDLC = 0, MODE_RAW, MODE_G704};
  1949. +enum rx_tx_bit {
  1950. + TX_BIT = 0,
  1951. + RX_BIT = 1
  1952. +};
  1953. +enum chan_bit {
  1954. + CHAN_0 = (1 << 0),
  1955. + CHAN_1 = (1 << 1),
  1956. + CHAN_2 = (1 << 2),
  1957. + CHAN_3 = (1 << 3),
  1958. + CHAN_4 = (1 << 4),
  1959. + CHAN_5 = (1 << 5),
  1960. + CHAN_6 = (1 << 6),
  1961. + CHAN_7 = (1 << 7),
  1962. + CHAN_8 = (1 << 8),
  1963. + CHAN_9 = (1 << 9),
  1964. + CHAN_10 = (1 << 10),
  1965. + CHAN_11 = (1 << 11),
  1966. + CHAN_12 = (1 << 12),
  1967. + CHAN_13 = (1 << 13),
  1968. + CHAN_14 = (1 << 14),
  1969. + CHAN_15 = (1 << 15)
  1970. +};
  1971. +
  1972. +enum alignment { NOT_ALIGNED = 0, EVEN_FIRST, ODD_FIRST };
  1973. +
  1974. +#ifdef __ARMEB__
  1975. +typedef struct sk_buff buffer_t;
  1976. +#define free_buffer dev_kfree_skb
  1977. +#define free_buffer_irq dev_kfree_skb_irq
  1978. +#else
  1979. +typedef void buffer_t;
  1980. +#define free_buffer kfree
  1981. +#define free_buffer_irq kfree
  1982. +#endif
  1983. +
  1984. +struct hss_device {
  1985. + struct port *port;
  1986. + unsigned int open_count, excl_open;
  1987. + unsigned long tx_loc, rx_loc; /* bytes */
  1988. + unsigned long tx_frame, rx_frame; /* Frames */
  1989. + u8 id, chan_count;
  1990. + u8 log_channels[MAX_CHANNELS];
  1991. +
  1992. + u8 *rx_buf;
  1993. + u8 *tx_buf;
  1994. +
  1995. + size_t rx_buffer_size;
  1996. + size_t rx_period_size;
  1997. + size_t tx_buffer_size;
  1998. + size_t tx_period_size;
  1999. +
  2000. + void (*rx_callback)(void *data);
  2001. + void *rx_data;
  2002. + void (*tx_callback)(void *data);
  2003. + void *tx_data;
  2004. + void *private_data;
  2005. +};
  2006. +
  2007. +extern struct hss_device *hss_handle[32];
  2008. +extern struct port *hss_port[2];
  2009. +
  2010. +struct port {
  2011. + unsigned char init;
  2012. +
  2013. + struct device *dev;
  2014. +
  2015. + struct tasklet_struct task;
  2016. + unsigned int id;
  2017. + unsigned long chan_rx_bitmap;
  2018. + unsigned long chan_tx_bitmap;
  2019. + unsigned char chan_open;
  2020. +
  2021. + /* the following fields must be protected by npe_lock */
  2022. + enum mode mode;
  2023. + unsigned int clock_type, clock_rate, loopback;
  2024. + unsigned int frame_size, frame_sync_offset;
  2025. + unsigned int next_rx_frame;
  2026. +
  2027. + struct hss_device *chan_devices[MAX_CHAN_DEVICES];
  2028. + u32 chan_tx_buf_phys, chan_rx_buf_phys;
  2029. + u32 chan_tx_pointers_phys;
  2030. + u32 *chan_tx_pointers;
  2031. + u8 *chan_rx_buf;
  2032. + u8 *chan_tx_buf;
  2033. + u8 *tx_lists[CHAN_TX_LISTS][8];
  2034. + u8 *rx_frames[8][CHAN_TX_LISTS];
  2035. + unsigned int chan_open_count, hdlc_open;
  2036. + unsigned int chan_started, initialized, just_set_offset;
  2037. + unsigned int chan_last_rx, chan_last_tx;
  2038. +
  2039. + /* assigned channels, may be invalid with given frame length or mode */
  2040. + u8 channels[MAX_CHANNELS];
  2041. + int msg_count;
  2042. +};
  2043. +
  2044. +/* NPE message structure */
  2045. +struct msg {
  2046. +#ifdef __ARMEB__
  2047. + u8 cmd, unused, hss_port, index;
  2048. + union {
  2049. + struct { u8 data8a, data8b, data8c, data8d; };
  2050. + struct { u16 data16a, data16b; };
  2051. + struct { u32 data32; };
  2052. + };
  2053. +#else
  2054. + u8 index, hss_port, unused, cmd;
  2055. + union {
  2056. + struct { u8 data8d, data8c, data8b, data8a; };
  2057. + struct { u16 data16b, data16a; };
  2058. + struct { u32 data32; };
  2059. + };
  2060. +#endif
  2061. +};
  2062. +
  2063. +#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \
  2064. + (n) * sizeof(struct desc))
  2065. +#define rx_desc_ptr(port, n) (&(port)->desc_tab[n])
  2066. +
  2067. +#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \
  2068. + ((n) + RX_DESCS) * sizeof(struct desc))
  2069. +#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS])
  2070. +
  2071. +int hss_prepare_chan(struct port *port);
  2072. +void hss_chan_stop(struct port *port);
  2073. +
  2074. +struct hss_device *hss_init(int id, int channel);
  2075. +int hss_chan_open(struct hss_device *hdev);
  2076. +int hss_chan_close(struct hss_device *hdev);
  2077. +
  2078. +int hss_set_tx_callback(struct hss_device *hdev, void (*tx_callback)(void *), void *tx_data);
  2079. +int hss_set_rx_callback(struct hss_device *hdev, void (*rx_callback)(void *), void *rx_data);
  2080. +int hss_tx_start(struct hss_device *hdev);
  2081. +int hss_tx_stop(struct hss_device *hdev);
  2082. +int hss_rx_start(struct hss_device *hdev);
  2083. +int hss_rx_stop(struct hss_device *hdev);
  2084. +
  2085. +int hss_config_rx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size);
  2086. +int hss_config_tx_dma(struct hss_device *hdev, void *buf, size_t buffer_size, size_t period_size);
  2087. +unsigned long hss_curr_offset_rx(struct hss_device *hdev);
  2088. +unsigned long hss_curr_offset_tx(struct hss_device *hdev);
  2089. +