Mahesh Kumar Sharma | 41a4d38 | 2017-01-17 17:00:51 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. |
| 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify |
| 4 | * it under the terms of the GNU General Public License version 2 and |
| 5 | * only version 2 as published by the Free Software Foundation. |
| 6 | * |
| 7 | * This program is distributed in the hope that it will be useful, |
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 10 | * GNU General Public License for more details. |
| 11 | */ |
| 12 | #include <linux/init.h> |
| 13 | #include <linux/kernel.h> |
| 14 | #include <linux/module.h> |
| 15 | #include <linux/of_gpio.h> |
| 16 | #include <linux/delay.h> |
| 17 | #include <linux/gpio.h> |
| 18 | #include <linux/debugfs.h> |
| 19 | #include <linux/ratelimit.h> |
| 20 | #include <linux/slab.h> |
| 21 | #include <sound/pcm.h> |
| 22 | #include <sound/pcm_params.h> |
| 23 | #include <sound/soc.h> |
| 24 | #include <sound/soc-dapm.h> |
| 25 | #include <sound/tlv.h> |
| 26 | #include <btfm_slim.h> |
| 27 | #include <btfm_slim_wcn3990.h> |
| 28 | #include <linux/bluetooth-power.h> |
| 29 | |
| 30 | int btfm_slim_write(struct btfmslim *btfmslim, |
| 31 | uint16_t reg, int bytes, void *src, uint8_t pgd) |
| 32 | { |
| 33 | int ret, i; |
| 34 | struct slim_ele_access msg; |
| 35 | int slim_write_tries = SLIM_SLAVE_RW_MAX_TRIES; |
| 36 | |
| 37 | BTFMSLIM_DBG("Write to %s", pgd?"PGD":"IFD"); |
| 38 | msg.start_offset = SLIM_SLAVE_REG_OFFSET + reg; |
| 39 | msg.num_bytes = bytes; |
| 40 | msg.comp = NULL; |
| 41 | |
| 42 | for ( ; slim_write_tries != 0; slim_write_tries--) { |
| 43 | mutex_lock(&btfmslim->xfer_lock); |
| 44 | ret = slim_change_val_element(pgd ? btfmslim->slim_pgd : |
| 45 | &btfmslim->slim_ifd, &msg, src, bytes); |
| 46 | mutex_unlock(&btfmslim->xfer_lock); |
| 47 | if (ret == 0) |
| 48 | break; |
| 49 | usleep_range(5000, 5100); |
| 50 | } |
| 51 | |
| 52 | if (ret) { |
| 53 | BTFMSLIM_ERR("failed (%d)", ret); |
| 54 | return ret; |
| 55 | } |
| 56 | |
| 57 | for (i = 0; i < bytes; i++) |
| 58 | BTFMSLIM_DBG("Write 0x%02x to reg 0x%x", ((uint8_t *)src)[i], |
| 59 | reg + i); |
| 60 | return 0; |
| 61 | } |
| 62 | |
| 63 | int btfm_slim_write_pgd(struct btfmslim *btfmslim, |
| 64 | uint16_t reg, int bytes, void *src) |
| 65 | { |
| 66 | return btfm_slim_write(btfmslim, reg, bytes, src, PGD); |
| 67 | } |
| 68 | |
| 69 | int btfm_slim_write_inf(struct btfmslim *btfmslim, |
| 70 | uint16_t reg, int bytes, void *src) |
| 71 | { |
| 72 | return btfm_slim_write(btfmslim, reg, bytes, src, IFD); |
| 73 | } |
| 74 | |
| 75 | int btfm_slim_read(struct btfmslim *btfmslim, unsigned short reg, |
| 76 | int bytes, void *dest, uint8_t pgd) |
| 77 | { |
| 78 | int ret, i; |
| 79 | struct slim_ele_access msg; |
| 80 | int slim_read_tries = SLIM_SLAVE_RW_MAX_TRIES; |
| 81 | |
| 82 | BTFMSLIM_DBG("Read from %s", pgd?"PGD":"IFD"); |
| 83 | msg.start_offset = SLIM_SLAVE_REG_OFFSET + reg; |
| 84 | msg.num_bytes = bytes; |
| 85 | msg.comp = NULL; |
| 86 | |
| 87 | for ( ; slim_read_tries != 0; slim_read_tries--) { |
| 88 | mutex_lock(&btfmslim->xfer_lock); |
| 89 | ret = slim_request_val_element(pgd ? btfmslim->slim_pgd : |
| 90 | &btfmslim->slim_ifd, &msg, dest, bytes); |
| 91 | mutex_unlock(&btfmslim->xfer_lock); |
| 92 | if (ret == 0) |
| 93 | break; |
| 94 | usleep_range(5000, 5100); |
| 95 | } |
| 96 | |
| 97 | if (ret) |
| 98 | BTFMSLIM_ERR("failed (%d)", ret); |
| 99 | |
| 100 | for (i = 0; i < bytes; i++) |
| 101 | BTFMSLIM_DBG("Read 0x%02x from reg 0x%x", ((uint8_t *)dest)[i], |
| 102 | reg + i); |
| 103 | |
| 104 | return 0; |
| 105 | } |
| 106 | |
| 107 | int btfm_slim_read_pgd(struct btfmslim *btfmslim, |
| 108 | uint16_t reg, int bytes, void *dest) |
| 109 | { |
| 110 | return btfm_slim_read(btfmslim, reg, bytes, dest, PGD); |
| 111 | } |
| 112 | |
| 113 | int btfm_slim_read_inf(struct btfmslim *btfmslim, |
| 114 | uint16_t reg, int bytes, void *dest) |
| 115 | { |
| 116 | return btfm_slim_read(btfmslim, reg, bytes, dest, IFD); |
| 117 | } |
| 118 | |
| 119 | int btfm_slim_enable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, |
| 120 | uint8_t rxport, uint32_t rates, uint8_t grp, uint8_t nchan) |
| 121 | { |
| 122 | int ret, i; |
| 123 | struct slim_ch prop; |
| 124 | struct btfmslim_ch *chan = ch; |
| 125 | uint16_t ch_h[2]; |
| 126 | |
| 127 | if (!btfmslim || !ch) |
| 128 | return -EINVAL; |
| 129 | |
Rupesh Tatiya | 3815c79 | 2017-02-17 12:58:01 +0530 | [diff] [blame] | 130 | BTFMSLIM_DBG("port: %d ch: %d", ch->port, ch->ch); |
Mahesh Kumar Sharma | 41a4d38 | 2017-01-17 17:00:51 -0800 | [diff] [blame] | 131 | |
| 132 | /* Define the channel with below parameters */ |
Sungjun Park | ea258e4 | 2017-10-18 19:08:25 -0700 | [diff] [blame] | 133 | prop.prot = SLIM_AUTO_ISO; |
| 134 | prop.baser = ((rates == 44100) || (rates == 88200)) ? |
| 135 | SLIM_RATE_11025HZ : SLIM_RATE_4000HZ; |
| 136 | prop.dataf = ((rates == 48000) || (rates == 44100) || |
| 137 | (rates == 88200) || (rates == 96000)) ? |
| 138 | SLIM_CH_DATAF_NOT_DEFINED : SLIM_CH_DATAF_LPCM_AUDIO; |
Mahesh Kumar Sharma | 41a4d38 | 2017-01-17 17:00:51 -0800 | [diff] [blame] | 139 | prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE; |
Sungjun Park | ea258e4 | 2017-10-18 19:08:25 -0700 | [diff] [blame] | 140 | prop.ratem = ((rates == 44100) || (rates == 88200)) ? |
| 141 | (rates/11025) : (rates/4000); |
Mahesh Kumar Sharma | 41a4d38 | 2017-01-17 17:00:51 -0800 | [diff] [blame] | 142 | prop.sampleszbits = 16; |
| 143 | |
| 144 | ch_h[0] = ch->ch_hdl; |
| 145 | ch_h[1] = (grp) ? (ch+1)->ch_hdl : 0; |
| 146 | |
Sungjun Park | ea258e4 | 2017-10-18 19:08:25 -0700 | [diff] [blame] | 147 | BTFMSLIM_INFO("channel define - prot:%d, dataf:%d, auxf:%d", |
| 148 | prop.prot, prop.dataf, prop.auxf); |
| 149 | BTFMSLIM_INFO("channel define - rates:%d, baser:%d, ratem:%d", |
| 150 | rates, prop.baser, prop.ratem); |
| 151 | |
Mahesh Kumar Sharma | 41a4d38 | 2017-01-17 17:00:51 -0800 | [diff] [blame] | 152 | ret = slim_define_ch(btfmslim->slim_pgd, &prop, ch_h, nchan, grp, |
| 153 | &ch->grph); |
| 154 | if (ret < 0) { |
| 155 | BTFMSLIM_ERR("slim_define_ch failed ret[%d]", ret); |
| 156 | goto error; |
| 157 | } |
| 158 | |
| 159 | for (i = 0; i < nchan; i++, ch++) { |
| 160 | /* Enable port through registration setting */ |
| 161 | if (btfmslim->vendor_port_en) { |
| 162 | ret = btfmslim->vendor_port_en(btfmslim, ch->port, |
| 163 | rxport, 1); |
| 164 | if (ret < 0) { |
| 165 | BTFMSLIM_ERR("vendor_port_en failed ret[%d]", |
| 166 | ret); |
| 167 | goto error; |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | if (rxport) { |
| 172 | BTFMSLIM_INFO("slim_connect_sink(port: %d, ch: %d)", |
| 173 | ch->port, ch->ch); |
| 174 | /* Connect Port with channel given by Machine driver*/ |
| 175 | ret = slim_connect_sink(btfmslim->slim_pgd, |
| 176 | &ch->port_hdl, 1, ch->ch_hdl); |
| 177 | if (ret < 0) { |
| 178 | BTFMSLIM_ERR("slim_connect_sink failed ret[%d]", |
| 179 | ret); |
| 180 | goto remove_channel; |
| 181 | } |
| 182 | |
| 183 | } else { |
| 184 | BTFMSLIM_INFO("slim_connect_src(port: %d, ch: %d)", |
| 185 | ch->port, ch->ch); |
| 186 | /* Connect Port with channel given by Machine driver*/ |
| 187 | ret = slim_connect_src(btfmslim->slim_pgd, ch->port_hdl, |
| 188 | ch->ch_hdl); |
| 189 | if (ret < 0) { |
| 190 | BTFMSLIM_ERR("slim_connect_src failed ret[%d]", |
| 191 | ret); |
| 192 | goto remove_channel; |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | /* Activate the channel immediately */ |
| 198 | BTFMSLIM_INFO( |
| 199 | "port: %d, ch: %d, grp: %d, ch->grph: 0x%x, ch_hdl: 0x%x", |
| 200 | chan->port, chan->ch, grp, chan->grph, chan->ch_hdl); |
| 201 | ret = slim_control_ch(btfmslim->slim_pgd, (grp ? chan->grph : |
| 202 | chan->ch_hdl), SLIM_CH_ACTIVATE, true); |
| 203 | if (ret < 0) { |
| 204 | BTFMSLIM_ERR("slim_control_ch failed ret[%d]", ret); |
| 205 | goto remove_channel; |
| 206 | } |
| 207 | |
| 208 | error: |
| 209 | return ret; |
| 210 | |
| 211 | remove_channel: |
| 212 | /* Remove the channel immediately*/ |
| 213 | ret = slim_control_ch(btfmslim->slim_pgd, (grp ? ch->grph : ch->ch_hdl), |
| 214 | SLIM_CH_REMOVE, true); |
| 215 | if (ret < 0) |
| 216 | BTFMSLIM_ERR("slim_control_ch failed ret[%d]", ret); |
| 217 | |
| 218 | return ret; |
| 219 | } |
| 220 | |
| 221 | int btfm_slim_disable_ch(struct btfmslim *btfmslim, struct btfmslim_ch *ch, |
| 222 | uint8_t rxport, uint8_t grp, uint8_t nchan) |
| 223 | { |
| 224 | int ret, i; |
| 225 | |
| 226 | if (!btfmslim || !ch) |
| 227 | return -EINVAL; |
| 228 | |
| 229 | BTFMSLIM_INFO("port:%d, grp: %d, ch->grph:0x%x, ch->ch_hdl:0x%x ", |
| 230 | ch->port, grp, ch->grph, ch->ch_hdl); |
| 231 | /* Remove the channel immediately*/ |
| 232 | ret = slim_control_ch(btfmslim->slim_pgd, (grp ? ch->grph : ch->ch_hdl), |
| 233 | SLIM_CH_REMOVE, true); |
| 234 | if (ret < 0) { |
| 235 | BTFMSLIM_ERR("slim_control_ch failed ret[%d]", ret); |
| 236 | ret = slim_disconnect_ports(btfmslim->slim_pgd, |
| 237 | &ch->port_hdl, 1); |
| 238 | if (ret < 0) { |
| 239 | BTFMSLIM_ERR("slim_disconnect_ports failed ret[%d]", |
| 240 | ret); |
| 241 | goto error; |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | /* Disable port through registration setting */ |
| 246 | for (i = 0; i < nchan; i++, ch++) { |
| 247 | if (btfmslim->vendor_port_en) { |
| 248 | ret = btfmslim->vendor_port_en(btfmslim, ch->port, |
| 249 | rxport, 0); |
| 250 | if (ret < 0) { |
| 251 | BTFMSLIM_ERR("vendor_port_en failed ret[%d]", |
| 252 | ret); |
| 253 | break; |
| 254 | } |
| 255 | } |
| 256 | } |
| 257 | error: |
| 258 | return ret; |
| 259 | } |
| 260 | static int btfm_slim_get_logical_addr(struct slim_device *slim) |
| 261 | { |
| 262 | int ret = 0; |
| 263 | const unsigned long timeout = jiffies + |
| 264 | msecs_to_jiffies(SLIM_SLAVE_PRESENT_TIMEOUT); |
| 265 | |
| 266 | do { |
| 267 | ret = slim_get_logical_addr(slim, slim->e_addr, |
| 268 | ARRAY_SIZE(slim->e_addr), &slim->laddr); |
| 269 | if (!ret) { |
| 270 | BTFMSLIM_DBG("Assigned l-addr: 0x%x", slim->laddr); |
| 271 | break; |
| 272 | } |
| 273 | /* Give SLIMBUS time to report present and be ready. */ |
| 274 | usleep_range(1000, 1100); |
| 275 | BTFMSLIM_DBG("retyring get logical addr"); |
| 276 | } while (time_before(jiffies, timeout)); |
| 277 | |
| 278 | return ret; |
| 279 | } |
| 280 | |
| 281 | static int btfm_slim_alloc_port(struct btfmslim *btfmslim) |
| 282 | { |
| 283 | int ret = -EINVAL, i; |
| 284 | struct btfmslim_ch *rx_chs; |
| 285 | struct btfmslim_ch *tx_chs; |
| 286 | |
| 287 | if (!btfmslim) |
| 288 | return ret; |
| 289 | |
| 290 | rx_chs = btfmslim->rx_chs; |
| 291 | tx_chs = btfmslim->tx_chs; |
| 292 | |
| 293 | if (!rx_chs || !tx_chs) |
| 294 | return ret; |
| 295 | |
| 296 | BTFMSLIM_DBG("Rx: id\tname\tport\thdl\tch\tch_hdl"); |
| 297 | for (i = 0 ; (rx_chs->port != BTFM_SLIM_PGD_PORT_LAST) && |
| 298 | (i < BTFM_SLIM_NUM_CODEC_DAIS); i++, rx_chs++) { |
| 299 | |
| 300 | /* Get Rx port handler from slimbus driver based |
| 301 | * on port number |
| 302 | */ |
| 303 | ret = slim_get_slaveport(btfmslim->slim_pgd->laddr, |
| 304 | rx_chs->port, &rx_chs->port_hdl, SLIM_SINK); |
| 305 | if (ret < 0) { |
| 306 | BTFMSLIM_ERR("slave port failure port#%d - ret[%d]", |
| 307 | rx_chs->port, SLIM_SINK); |
| 308 | return ret; |
| 309 | } |
| 310 | BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", rx_chs->id, |
| 311 | rx_chs->name, rx_chs->port, rx_chs->port_hdl, |
| 312 | rx_chs->ch, rx_chs->ch_hdl); |
| 313 | } |
| 314 | |
| 315 | BTFMSLIM_DBG("Tx: id\tname\tport\thdl\tch\tch_hdl"); |
| 316 | for (i = 0; (tx_chs->port != BTFM_SLIM_PGD_PORT_LAST) && |
| 317 | (i < BTFM_SLIM_NUM_CODEC_DAIS); i++, tx_chs++) { |
| 318 | |
| 319 | /* Get Tx port handler from slimbus driver based |
| 320 | * on port number |
| 321 | */ |
| 322 | ret = slim_get_slaveport(btfmslim->slim_pgd->laddr, |
| 323 | tx_chs->port, &tx_chs->port_hdl, SLIM_SRC); |
| 324 | if (ret < 0) { |
| 325 | BTFMSLIM_ERR("slave port failure port#%d - ret[%d]", |
| 326 | tx_chs->port, SLIM_SRC); |
| 327 | return ret; |
| 328 | } |
| 329 | BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", tx_chs->id, |
| 330 | tx_chs->name, tx_chs->port, tx_chs->port_hdl, |
| 331 | tx_chs->ch, tx_chs->ch_hdl); |
| 332 | } |
| 333 | return ret; |
| 334 | } |
| 335 | |
| 336 | int btfm_slim_hw_init(struct btfmslim *btfmslim) |
| 337 | { |
| 338 | int ret; |
| 339 | |
| 340 | BTFMSLIM_DBG(""); |
| 341 | if (!btfmslim) |
| 342 | return -EINVAL; |
| 343 | |
| 344 | if (btfmslim->enabled) { |
| 345 | BTFMSLIM_DBG("Already enabled"); |
| 346 | return 0; |
| 347 | } |
| 348 | mutex_lock(&btfmslim->io_lock); |
| 349 | |
| 350 | /* Assign Logical Address for PGD (Ported Generic Device) |
| 351 | * enumeration address |
| 352 | */ |
| 353 | ret = btfm_slim_get_logical_addr(btfmslim->slim_pgd); |
| 354 | if (ret) { |
| 355 | BTFMSLIM_ERR("failed to get slimbus %s logical address: %d", |
| 356 | btfmslim->slim_pgd->name, ret); |
| 357 | goto error; |
| 358 | } |
| 359 | |
| 360 | /* Assign Logical Address for Ported Generic Device |
| 361 | * enumeration address |
| 362 | */ |
| 363 | ret = btfm_slim_get_logical_addr(&btfmslim->slim_ifd); |
| 364 | if (ret) { |
| 365 | BTFMSLIM_ERR("failed to get slimbus %s logical address: %d", |
| 366 | btfmslim->slim_ifd.name, ret); |
| 367 | goto error; |
| 368 | } |
| 369 | |
| 370 | /* Allocate ports with logical address to get port handler from |
| 371 | * slimbus driver |
| 372 | */ |
| 373 | ret = btfm_slim_alloc_port(btfmslim); |
| 374 | if (ret) |
| 375 | goto error; |
| 376 | |
| 377 | /* Start vendor specific initialization and get port information */ |
| 378 | if (btfmslim->vendor_init) |
| 379 | ret = btfmslim->vendor_init(btfmslim); |
| 380 | |
| 381 | /* Only when all registers read/write successfully, it set to |
| 382 | * enabled status |
| 383 | */ |
| 384 | btfmslim->enabled = 1; |
| 385 | error: |
| 386 | mutex_unlock(&btfmslim->io_lock); |
| 387 | return ret; |
| 388 | } |
| 389 | |
| 390 | |
| 391 | int btfm_slim_hw_deinit(struct btfmslim *btfmslim) |
| 392 | { |
| 393 | int ret = 0; |
| 394 | |
| 395 | if (!btfmslim) |
| 396 | return -EINVAL; |
| 397 | |
| 398 | if (!btfmslim->enabled) { |
| 399 | BTFMSLIM_DBG("Already disabled"); |
| 400 | return 0; |
| 401 | } |
| 402 | mutex_lock(&btfmslim->io_lock); |
| 403 | btfmslim->enabled = 0; |
| 404 | mutex_unlock(&btfmslim->io_lock); |
| 405 | return ret; |
| 406 | } |
| 407 | |
| 408 | static int btfm_slim_get_dt_info(struct btfmslim *btfmslim) |
| 409 | { |
| 410 | int ret = 0; |
| 411 | struct slim_device *slim = btfmslim->slim_pgd; |
| 412 | struct slim_device *slim_ifd = &btfmslim->slim_ifd; |
| 413 | struct property *prop; |
| 414 | |
| 415 | if (!slim || !slim_ifd) |
| 416 | return -EINVAL; |
| 417 | |
| 418 | if (slim->dev.of_node) { |
| 419 | BTFMSLIM_DBG("Platform data from device tree (%s)", |
| 420 | slim->name); |
| 421 | ret = of_property_read_string(slim->dev.of_node, |
| 422 | "qcom,btfm-slim-ifd", &slim_ifd->name); |
| 423 | if (ret) { |
| 424 | BTFMSLIM_ERR("Looking up %s property in node %s failed", |
| 425 | "qcom,btfm-slim-ifd", |
| 426 | slim->dev.of_node->full_name); |
| 427 | return -ENODEV; |
| 428 | } |
| 429 | BTFMSLIM_DBG("qcom,btfm-slim-ifd (%s)", slim_ifd->name); |
| 430 | |
| 431 | prop = of_find_property(slim->dev.of_node, |
| 432 | "qcom,btfm-slim-ifd-elemental-addr", NULL); |
| 433 | if (!prop) { |
| 434 | BTFMSLIM_ERR("Looking up %s property in node %s failed", |
| 435 | "qcom,btfm-slim-ifd-elemental-addr", |
| 436 | slim->dev.of_node->full_name); |
| 437 | return -ENODEV; |
| 438 | } else if (prop->length != 6) { |
| 439 | BTFMSLIM_ERR( |
| 440 | "invalid codec slim ifd addr. addr length= %d", |
| 441 | prop->length); |
| 442 | return -ENODEV; |
| 443 | } |
| 444 | memcpy(slim_ifd->e_addr, prop->value, 6); |
| 445 | BTFMSLIM_DBG( |
| 446 | "PGD Enum Addr: %.02x:%.02x:%.02x:%.02x:%.02x: %.02x", |
| 447 | slim->e_addr[0], slim->e_addr[1], slim->e_addr[2], |
| 448 | slim->e_addr[3], slim->e_addr[4], slim->e_addr[5]); |
| 449 | BTFMSLIM_DBG( |
| 450 | "IFD Enum Addr: %.02x:%.02x:%.02x:%.02x:%.02x: %.02x", |
| 451 | slim_ifd->e_addr[0], slim_ifd->e_addr[1], |
| 452 | slim_ifd->e_addr[2], slim_ifd->e_addr[3], |
| 453 | slim_ifd->e_addr[4], slim_ifd->e_addr[5]); |
| 454 | } else { |
| 455 | BTFMSLIM_ERR("Platform data is not valid"); |
| 456 | } |
| 457 | |
| 458 | return ret; |
| 459 | } |
| 460 | |
| 461 | static int btfm_slim_probe(struct slim_device *slim) |
| 462 | { |
| 463 | int ret = 0; |
| 464 | struct btfmslim *btfm_slim; |
| 465 | |
| 466 | BTFMSLIM_DBG(""); |
| 467 | if (!slim->ctrl) |
| 468 | return -EINVAL; |
| 469 | |
| 470 | /* Allocation btfmslim data pointer */ |
| 471 | btfm_slim = kzalloc(sizeof(struct btfmslim), GFP_KERNEL); |
| 472 | if (btfm_slim == NULL) { |
| 473 | BTFMSLIM_ERR("error, allocation failed"); |
| 474 | return -ENOMEM; |
| 475 | } |
| 476 | /* BTFM Slimbus driver control data configuration */ |
| 477 | btfm_slim->slim_pgd = slim; |
| 478 | |
| 479 | /* Assign vendor specific function */ |
| 480 | btfm_slim->rx_chs = SLIM_SLAVE_RXPORT; |
| 481 | btfm_slim->tx_chs = SLIM_SLAVE_TXPORT; |
| 482 | btfm_slim->vendor_init = SLIM_SLAVE_INIT; |
| 483 | btfm_slim->vendor_port_en = SLIM_SLAVE_PORT_EN; |
| 484 | |
| 485 | /* Created Mutex for slimbus data transfer */ |
| 486 | mutex_init(&btfm_slim->io_lock); |
| 487 | mutex_init(&btfm_slim->xfer_lock); |
| 488 | |
| 489 | /* Get Device tree node for Interface Device enumeration address */ |
| 490 | ret = btfm_slim_get_dt_info(btfm_slim); |
| 491 | if (ret) |
| 492 | goto dealloc; |
| 493 | |
| 494 | /* Add Interface Device for slimbus driver */ |
| 495 | ret = slim_add_device(btfm_slim->slim_pgd->ctrl, &btfm_slim->slim_ifd); |
| 496 | if (ret) { |
| 497 | BTFMSLIM_ERR("error, adding SLIMBUS device failed"); |
| 498 | goto dealloc; |
| 499 | } |
| 500 | |
| 501 | /* Platform driver data allocation */ |
| 502 | slim->dev.platform_data = btfm_slim; |
| 503 | |
| 504 | /* Driver specific data allocation */ |
| 505 | btfm_slim->dev = &slim->dev; |
| 506 | ret = btfm_slim_register_codec(&slim->dev); |
Satish kumar sugasi | bcf528a | 2017-07-27 13:37:22 -0700 | [diff] [blame] | 507 | if (ret) { |
| 508 | BTFMSLIM_ERR("error, registering slimbus codec failed"); |
| 509 | goto free; |
| 510 | } |
Mahesh Kumar Sharma | 41a4d38 | 2017-01-17 17:00:51 -0800 | [diff] [blame] | 511 | ret = bt_register_slimdev(&slim->dev); |
Satish kumar sugasi | bcf528a | 2017-07-27 13:37:22 -0700 | [diff] [blame] | 512 | if (ret < 0) { |
| 513 | btfm_slim_unregister_codec(&slim->dev); |
| 514 | goto free; |
| 515 | } |
Mahesh Kumar Sharma | 41a4d38 | 2017-01-17 17:00:51 -0800 | [diff] [blame] | 516 | return ret; |
Satish kumar sugasi | bcf528a | 2017-07-27 13:37:22 -0700 | [diff] [blame] | 517 | free: |
| 518 | slim_remove_device(&btfm_slim->slim_ifd); |
Mahesh Kumar Sharma | 41a4d38 | 2017-01-17 17:00:51 -0800 | [diff] [blame] | 519 | dealloc: |
| 520 | mutex_destroy(&btfm_slim->io_lock); |
| 521 | mutex_destroy(&btfm_slim->xfer_lock); |
| 522 | kfree(btfm_slim); |
| 523 | return ret; |
| 524 | } |
| 525 | static int btfm_slim_remove(struct slim_device *slim) |
| 526 | { |
| 527 | struct btfmslim *btfm_slim = slim->dev.platform_data; |
| 528 | |
| 529 | BTFMSLIM_DBG(""); |
| 530 | mutex_destroy(&btfm_slim->io_lock); |
| 531 | mutex_destroy(&btfm_slim->xfer_lock); |
| 532 | snd_soc_unregister_codec(&slim->dev); |
| 533 | |
| 534 | BTFMSLIM_DBG("slim_remove_device() - btfm_slim->slim_ifd"); |
| 535 | slim_remove_device(&btfm_slim->slim_ifd); |
| 536 | |
| 537 | kfree(btfm_slim); |
| 538 | |
| 539 | BTFMSLIM_DBG("slim_remove_device() - btfm_slim->slim_pgd"); |
| 540 | slim_remove_device(slim); |
| 541 | return 0; |
| 542 | } |
| 543 | |
| 544 | static const struct slim_device_id btfm_slim_id[] = { |
| 545 | {SLIM_SLAVE_COMPATIBLE_STR, 0}, |
| 546 | {} |
| 547 | }; |
| 548 | |
| 549 | static struct slim_driver btfm_slim_driver = { |
| 550 | .driver = { |
| 551 | .name = "btfmslim-driver", |
| 552 | .owner = THIS_MODULE, |
| 553 | }, |
| 554 | .probe = btfm_slim_probe, |
| 555 | .remove = btfm_slim_remove, |
| 556 | .id_table = btfm_slim_id |
| 557 | }; |
| 558 | |
| 559 | static int __init btfm_slim_init(void) |
| 560 | { |
| 561 | int ret; |
| 562 | |
| 563 | BTFMSLIM_DBG(""); |
| 564 | ret = slim_driver_register(&btfm_slim_driver); |
| 565 | if (ret) |
| 566 | BTFMSLIM_ERR("Failed to register slimbus driver: %d", ret); |
| 567 | return ret; |
| 568 | } |
| 569 | |
| 570 | static void __exit btfm_slim_exit(void) |
| 571 | { |
| 572 | BTFMSLIM_DBG(""); |
| 573 | slim_driver_unregister(&btfm_slim_driver); |
| 574 | } |
| 575 | |
| 576 | module_init(btfm_slim_init); |
| 577 | module_exit(btfm_slim_exit); |
| 578 | |
| 579 | MODULE_LICENSE("GPL v2"); |
| 580 | MODULE_DESCRIPTION("BTFM Slimbus Slave driver"); |