2 * Wireless Host Controller (WHC) initialization.
4 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <linux/kernel.h>
19 #include <linux/dma-mapping.h>
20 #include <linux/uwb/umc.h>
22 #include "../../wusbcore/wusbhc.h"
27 * Reset the host controller.
29 static void whc_hw_reset(struct whc
*whc
)
31 le_writel(WUSBCMD_WHCRESET
, whc
->base
+ WUSBCMD
);
32 whci_wait_for(&whc
->umc
->dev
, whc
->base
+ WUSBCMD
, WUSBCMD_WHCRESET
, 0,
36 static void whc_hw_init_di_buf(struct whc
*whc
)
40 /* Disable all entries in the Device Information buffer. */
41 for (d
= 0; d
< whc
->n_devices
; d
++)
42 whc
->di_buf
[d
].addr_sec_info
= WHC_DI_DISABLE
;
44 le_writeq(whc
->di_buf_dma
, whc
->base
+ WUSBDEVICEINFOADDR
);
47 static void whc_hw_init_dn_buf(struct whc
*whc
)
49 /* Clear the Device Notification buffer to ensure the V (valid)
51 memset(whc
->dn_buf
, 0, 4096);
53 le_writeq(whc
->dn_buf_dma
, whc
->base
+ WUSBDNTSBUFADDR
);
56 int whc_init(struct whc
*whc
)
60 resource_size_t start
, len
;
62 spin_lock_init(&whc
->lock
);
63 mutex_init(&whc
->mutex
);
64 init_waitqueue_head(&whc
->cmd_wq
);
65 init_waitqueue_head(&whc
->async_list_wq
);
66 init_waitqueue_head(&whc
->periodic_list_wq
);
67 whc
->workqueue
= create_singlethread_workqueue(dev_name(&whc
->umc
->dev
));
68 if (whc
->workqueue
== NULL
) {
72 INIT_WORK(&whc
->dn_work
, whc_dn_work
);
74 INIT_WORK(&whc
->async_work
, scan_async_work
);
75 INIT_LIST_HEAD(&whc
->async_list
);
76 INIT_LIST_HEAD(&whc
->async_removed_list
);
78 INIT_WORK(&whc
->periodic_work
, scan_periodic_work
);
79 for (i
= 0; i
< 5; i
++)
80 INIT_LIST_HEAD(&whc
->periodic_list
[i
]);
81 INIT_LIST_HEAD(&whc
->periodic_removed_list
);
83 /* Map HC registers. */
84 start
= whc
->umc
->resource
.start
;
85 len
= whc
->umc
->resource
.end
- start
+ 1;
86 if (!request_mem_region(start
, len
, "whci-hc")) {
87 dev_err(&whc
->umc
->dev
, "can't request HC region\n");
91 whc
->base_phys
= start
;
92 whc
->base
= ioremap(start
, len
);
94 dev_err(&whc
->umc
->dev
, "ioremap\n");
101 /* Read maximum number of devices, keys and MMC IEs. */
102 whcsparams
= le_readl(whc
->base
+ WHCSPARAMS
);
103 whc
->n_devices
= WHCSPARAMS_TO_N_DEVICES(whcsparams
);
104 whc
->n_keys
= WHCSPARAMS_TO_N_KEYS(whcsparams
);
105 whc
->n_mmc_ies
= WHCSPARAMS_TO_N_MMC_IES(whcsparams
);
107 dev_dbg(&whc
->umc
->dev
, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
108 whc
->n_devices
, whc
->n_keys
, whc
->n_mmc_ies
);
110 whc
->qset_pool
= dma_pool_create("qset", &whc
->umc
->dev
,
111 sizeof(struct whc_qset
), 64, 0);
112 if (whc
->qset_pool
== NULL
) {
124 /* Allocate and initialize a buffer for generic commands, the
125 Device Information buffer, and the Device Notification
128 whc
->gen_cmd_buf
= dma_alloc_coherent(&whc
->umc
->dev
, WHC_GEN_CMD_DATA_LEN
,
129 &whc
->gen_cmd_buf_dma
, GFP_KERNEL
);
130 if (whc
->gen_cmd_buf
== NULL
) {
135 whc
->dn_buf
= dma_alloc_coherent(&whc
->umc
->dev
,
136 sizeof(struct dn_buf_entry
) * WHC_N_DN_ENTRIES
,
137 &whc
->dn_buf_dma
, GFP_KERNEL
);
142 whc_hw_init_dn_buf(whc
);
144 whc
->di_buf
= dma_alloc_coherent(&whc
->umc
->dev
,
145 sizeof(struct di_buf_entry
) * whc
->n_devices
,
146 &whc
->di_buf_dma
, GFP_KERNEL
);
151 whc_hw_init_di_buf(whc
);
160 void whc_clean_up(struct whc
*whc
)
165 dma_free_coherent(&whc
->umc
->dev
, sizeof(struct di_buf_entry
) * whc
->n_devices
,
166 whc
->di_buf
, whc
->di_buf_dma
);
168 dma_free_coherent(&whc
->umc
->dev
, sizeof(struct dn_buf_entry
) * WHC_N_DN_ENTRIES
,
169 whc
->dn_buf
, whc
->dn_buf_dma
);
170 if (whc
->gen_cmd_buf
)
171 dma_free_coherent(&whc
->umc
->dev
, WHC_GEN_CMD_DATA_LEN
,
172 whc
->gen_cmd_buf
, whc
->gen_cmd_buf_dma
);
178 dma_pool_destroy(whc
->qset_pool
);
180 len
= whc
->umc
->resource
.end
- whc
->umc
->resource
.start
+ 1;
184 release_mem_region(whc
->base_phys
, len
);
187 destroy_workqueue(whc
->workqueue
);