| .. | .. |
|---|
| 38 | 38 | #define OMAP_HDQ_INT_STATUS_TXCOMPLETE BIT(2) |
|---|
| 39 | 39 | #define OMAP_HDQ_INT_STATUS_RXCOMPLETE BIT(1) |
|---|
| 40 | 40 | #define OMAP_HDQ_INT_STATUS_TIMEOUT BIT(0) |
|---|
| 41 | | -#define OMAP_HDQ_SYSCONFIG 0x14 |
|---|
| 42 | | -#define OMAP_HDQ_SYSCONFIG_SOFTRESET BIT(1) |
|---|
| 43 | | -#define OMAP_HDQ_SYSCONFIG_AUTOIDLE BIT(0) |
|---|
| 44 | | -#define OMAP_HDQ_SYSCONFIG_NOIDLE 0x0 |
|---|
| 45 | | -#define OMAP_HDQ_SYSSTATUS 0x18 |
|---|
| 46 | | -#define OMAP_HDQ_SYSSTATUS_RESETDONE BIT(0) |
|---|
| 47 | 41 | |
|---|
| 48 | 42 | #define OMAP_HDQ_FLAG_CLEAR 0 |
|---|
| 49 | 43 | #define OMAP_HDQ_FLAG_SET 1 |
|---|
| .. | .. |
|---|
| 60 | 54 | struct hdq_data { |
|---|
| 61 | 55 | struct device *dev; |
|---|
| 62 | 56 | void __iomem *hdq_base; |
|---|
| 63 | | - /* lock status update */ |
|---|
| 57 | + /* lock read/write/break operations */ |
|---|
| 64 | 58 | struct mutex hdq_mutex; |
|---|
| 65 | | - int hdq_usecount; |
|---|
| 59 | + /* interrupt status and a lock for it */ |
|---|
| 66 | 60 | u8 hdq_irqstatus; |
|---|
| 67 | | - /* device lock */ |
|---|
| 68 | 61 | spinlock_t hdq_spinlock; |
|---|
| 69 | | - /* |
|---|
| 70 | | - * Used to control the call to omap_hdq_get and omap_hdq_put. |
|---|
| 71 | | - * HDQ Protocol: Write the CMD|REG_address first, followed by |
|---|
| 72 | | - * the data wrire or read. |
|---|
| 73 | | - */ |
|---|
| 74 | | - int init_trans; |
|---|
| 75 | | - int rrw; |
|---|
| 76 | 62 | /* mode: 0-HDQ 1-W1 */ |
|---|
| 77 | 63 | int mode; |
|---|
| 78 | 64 | |
|---|
| .. | .. |
|---|
| 97 | 83 | __raw_writel(new_val, hdq_data->hdq_base + offset); |
|---|
| 98 | 84 | |
|---|
| 99 | 85 | return new_val; |
|---|
| 100 | | -} |
|---|
| 101 | | - |
|---|
| 102 | | -static void hdq_disable_interrupt(struct hdq_data *hdq_data, u32 offset, |
|---|
| 103 | | - u32 mask) |
|---|
| 104 | | -{ |
|---|
| 105 | | - u32 ie; |
|---|
| 106 | | - |
|---|
| 107 | | - ie = readl(hdq_data->hdq_base + offset); |
|---|
| 108 | | - writel(ie & mask, hdq_data->hdq_base + offset); |
|---|
| 109 | 86 | } |
|---|
| 110 | 87 | |
|---|
| 111 | 88 | /* |
|---|
| .. | .. |
|---|
| 142 | 119 | return ret; |
|---|
| 143 | 120 | } |
|---|
| 144 | 121 | |
|---|
| 122 | +/* Clear saved irqstatus after using an interrupt */ |
|---|
| 123 | +static u8 hdq_reset_irqstatus(struct hdq_data *hdq_data, u8 bits) |
|---|
| 124 | +{ |
|---|
| 125 | + unsigned long irqflags; |
|---|
| 126 | + u8 status; |
|---|
| 127 | + |
|---|
| 128 | + spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); |
|---|
| 129 | + status = hdq_data->hdq_irqstatus; |
|---|
| 130 | + /* this is a read-modify-write */ |
|---|
| 131 | + hdq_data->hdq_irqstatus &= ~bits; |
|---|
| 132 | + spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); |
|---|
| 133 | + |
|---|
| 134 | + return status; |
|---|
| 135 | +} |
|---|
| 136 | + |
|---|
| 145 | 137 | /* write out a byte and fill *status with HDQ_INT_STATUS */ |
|---|
| 146 | 138 | static int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status) |
|---|
| 147 | 139 | { |
|---|
| 148 | 140 | int ret; |
|---|
| 149 | 141 | u8 tmp_status; |
|---|
| 150 | | - unsigned long irqflags; |
|---|
| 142 | + |
|---|
| 143 | + ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); |
|---|
| 144 | + if (ret < 0) { |
|---|
| 145 | + ret = -EINTR; |
|---|
| 146 | + goto rtn; |
|---|
| 147 | + } |
|---|
| 148 | + |
|---|
| 149 | + if (hdq_data->hdq_irqstatus) |
|---|
| 150 | + dev_err(hdq_data->dev, "TX irqstatus not cleared (%02x)\n", |
|---|
| 151 | + hdq_data->hdq_irqstatus); |
|---|
| 151 | 152 | |
|---|
| 152 | 153 | *status = 0; |
|---|
| 153 | | - |
|---|
| 154 | | - spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); |
|---|
| 155 | | - /* clear interrupt flags via a dummy read */ |
|---|
| 156 | | - hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS); |
|---|
| 157 | | - /* ISR loads it with new INT_STATUS */ |
|---|
| 158 | | - hdq_data->hdq_irqstatus = 0; |
|---|
| 159 | | - spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); |
|---|
| 160 | 154 | |
|---|
| 161 | 155 | hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val); |
|---|
| 162 | 156 | |
|---|
| .. | .. |
|---|
| 165 | 159 | OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO); |
|---|
| 166 | 160 | /* wait for the TXCOMPLETE bit */ |
|---|
| 167 | 161 | ret = wait_event_timeout(hdq_wait_queue, |
|---|
| 168 | | - hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT); |
|---|
| 162 | + (hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_TXCOMPLETE), |
|---|
| 163 | + OMAP_HDQ_TIMEOUT); |
|---|
| 164 | + *status = hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_TXCOMPLETE); |
|---|
| 169 | 165 | if (ret == 0) { |
|---|
| 170 | 166 | dev_dbg(hdq_data->dev, "TX wait elapsed\n"); |
|---|
| 171 | 167 | ret = -ETIMEDOUT; |
|---|
| 172 | 168 | goto out; |
|---|
| 173 | 169 | } |
|---|
| 174 | 170 | |
|---|
| 175 | | - *status = hdq_data->hdq_irqstatus; |
|---|
| 176 | 171 | /* check irqstatus */ |
|---|
| 177 | 172 | if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) { |
|---|
| 178 | 173 | dev_dbg(hdq_data->dev, "timeout waiting for" |
|---|
| .. | .. |
|---|
| 191 | 186 | } |
|---|
| 192 | 187 | |
|---|
| 193 | 188 | out: |
|---|
| 189 | + mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 190 | +rtn: |
|---|
| 194 | 191 | return ret; |
|---|
| 195 | 192 | } |
|---|
| 196 | 193 | |
|---|
| .. | .. |
|---|
| 201 | 198 | unsigned long irqflags; |
|---|
| 202 | 199 | |
|---|
| 203 | 200 | spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); |
|---|
| 204 | | - hdq_data->hdq_irqstatus = hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS); |
|---|
| 201 | + hdq_data->hdq_irqstatus |= hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS); |
|---|
| 205 | 202 | spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); |
|---|
| 206 | 203 | dev_dbg(hdq_data->dev, "hdq_isr: %x\n", hdq_data->hdq_irqstatus); |
|---|
| 207 | 204 | |
|---|
| .. | .. |
|---|
| 237 | 234 | slave_found(master_dev, id); |
|---|
| 238 | 235 | } |
|---|
| 239 | 236 | |
|---|
| 240 | | -static int _omap_hdq_reset(struct hdq_data *hdq_data) |
|---|
| 241 | | -{ |
|---|
| 242 | | - int ret; |
|---|
| 243 | | - u8 tmp_status; |
|---|
| 244 | | - |
|---|
| 245 | | - hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, |
|---|
| 246 | | - OMAP_HDQ_SYSCONFIG_SOFTRESET); |
|---|
| 247 | | - /* |
|---|
| 248 | | - * Select HDQ/1W mode & enable clocks. |
|---|
| 249 | | - * It is observed that INT flags can't be cleared via a read and GO/INIT |
|---|
| 250 | | - * won't return to zero if interrupt is disabled. So we always enable |
|---|
| 251 | | - * interrupt. |
|---|
| 252 | | - */ |
|---|
| 253 | | - hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS, |
|---|
| 254 | | - OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | |
|---|
| 255 | | - OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK); |
|---|
| 256 | | - |
|---|
| 257 | | - /* wait for reset to complete */ |
|---|
| 258 | | - ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_SYSSTATUS, |
|---|
| 259 | | - OMAP_HDQ_SYSSTATUS_RESETDONE, OMAP_HDQ_FLAG_SET, &tmp_status); |
|---|
| 260 | | - if (ret) |
|---|
| 261 | | - dev_dbg(hdq_data->dev, "timeout waiting HDQ reset, %x", |
|---|
| 262 | | - tmp_status); |
|---|
| 263 | | - else { |
|---|
| 264 | | - hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS, |
|---|
| 265 | | - OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | |
|---|
| 266 | | - OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK | |
|---|
| 267 | | - hdq_data->mode); |
|---|
| 268 | | - hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, |
|---|
| 269 | | - OMAP_HDQ_SYSCONFIG_AUTOIDLE); |
|---|
| 270 | | - } |
|---|
| 271 | | - |
|---|
| 272 | | - return ret; |
|---|
| 273 | | -} |
|---|
| 274 | | - |
|---|
| 275 | 237 | /* Issue break pulse to the device */ |
|---|
| 276 | 238 | static int omap_hdq_break(struct hdq_data *hdq_data) |
|---|
| 277 | 239 | { |
|---|
| 278 | 240 | int ret = 0; |
|---|
| 279 | 241 | u8 tmp_status; |
|---|
| 280 | | - unsigned long irqflags; |
|---|
| 281 | 242 | |
|---|
| 282 | 243 | ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); |
|---|
| 283 | 244 | if (ret < 0) { |
|---|
| .. | .. |
|---|
| 286 | 247 | goto rtn; |
|---|
| 287 | 248 | } |
|---|
| 288 | 249 | |
|---|
| 289 | | - spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); |
|---|
| 290 | | - /* clear interrupt flags via a dummy read */ |
|---|
| 291 | | - hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS); |
|---|
| 292 | | - /* ISR loads it with new INT_STATUS */ |
|---|
| 293 | | - hdq_data->hdq_irqstatus = 0; |
|---|
| 294 | | - spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); |
|---|
| 250 | + if (hdq_data->hdq_irqstatus) |
|---|
| 251 | + dev_err(hdq_data->dev, "break irqstatus not cleared (%02x)\n", |
|---|
| 252 | + hdq_data->hdq_irqstatus); |
|---|
| 295 | 253 | |
|---|
| 296 | 254 | /* set the INIT and GO bit */ |
|---|
| 297 | 255 | hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, |
|---|
| .. | .. |
|---|
| 301 | 259 | |
|---|
| 302 | 260 | /* wait for the TIMEOUT bit */ |
|---|
| 303 | 261 | ret = wait_event_timeout(hdq_wait_queue, |
|---|
| 304 | | - hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT); |
|---|
| 262 | + (hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_TIMEOUT), |
|---|
| 263 | + OMAP_HDQ_TIMEOUT); |
|---|
| 264 | + tmp_status = hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_TIMEOUT); |
|---|
| 305 | 265 | if (ret == 0) { |
|---|
| 306 | 266 | dev_dbg(hdq_data->dev, "break wait elapsed\n"); |
|---|
| 307 | 267 | ret = -EINTR; |
|---|
| 308 | 268 | goto out; |
|---|
| 309 | 269 | } |
|---|
| 310 | 270 | |
|---|
| 311 | | - tmp_status = hdq_data->hdq_irqstatus; |
|---|
| 312 | 271 | /* check irqstatus */ |
|---|
| 313 | 272 | if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) { |
|---|
| 314 | 273 | dev_dbg(hdq_data->dev, "timeout waiting for TIMEOUT, %x\n", |
|---|
| 315 | | - tmp_status); |
|---|
| 274 | + tmp_status); |
|---|
| 316 | 275 | ret = -ETIMEDOUT; |
|---|
| 317 | 276 | goto out; |
|---|
| 318 | 277 | } |
|---|
| .. | .. |
|---|
| 357 | 316 | goto rtn; |
|---|
| 358 | 317 | } |
|---|
| 359 | 318 | |
|---|
| 360 | | - if (!hdq_data->hdq_usecount) { |
|---|
| 319 | + if (pm_runtime_suspended(hdq_data->dev)) { |
|---|
| 361 | 320 | ret = -EINVAL; |
|---|
| 362 | 321 | goto out; |
|---|
| 363 | 322 | } |
|---|
| .. | .. |
|---|
| 371 | 330 | */ |
|---|
| 372 | 331 | wait_event_timeout(hdq_wait_queue, |
|---|
| 373 | 332 | (hdq_data->hdq_irqstatus |
|---|
| 374 | | - & OMAP_HDQ_INT_STATUS_RXCOMPLETE), |
|---|
| 333 | + & (OMAP_HDQ_INT_STATUS_RXCOMPLETE | |
|---|
| 334 | + OMAP_HDQ_INT_STATUS_TIMEOUT)), |
|---|
| 375 | 335 | OMAP_HDQ_TIMEOUT); |
|---|
| 376 | | - |
|---|
| 336 | + status = hdq_reset_irqstatus(hdq_data, |
|---|
| 337 | + OMAP_HDQ_INT_STATUS_RXCOMPLETE | |
|---|
| 338 | + OMAP_HDQ_INT_STATUS_TIMEOUT); |
|---|
| 377 | 339 | hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, 0, |
|---|
| 378 | 340 | OMAP_HDQ_CTRL_STATUS_DIR); |
|---|
| 379 | | - status = hdq_data->hdq_irqstatus; |
|---|
| 341 | + |
|---|
| 380 | 342 | /* check irqstatus */ |
|---|
| 381 | 343 | if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) { |
|---|
| 382 | 344 | dev_dbg(hdq_data->dev, "timeout waiting for" |
|---|
| .. | .. |
|---|
| 384 | 346 | ret = -ETIMEDOUT; |
|---|
| 385 | 347 | goto out; |
|---|
| 386 | 348 | } |
|---|
| 349 | + } else { /* interrupt had occurred before hdq_read_byte was called */ |
|---|
| 350 | + hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_RXCOMPLETE); |
|---|
| 387 | 351 | } |
|---|
| 388 | 352 | /* the data is ready. Read it in! */ |
|---|
| 389 | 353 | *val = hdq_reg_in(hdq_data, OMAP_HDQ_RX_DATA); |
|---|
| .. | .. |
|---|
| 392 | 356 | rtn: |
|---|
| 393 | 357 | return ret; |
|---|
| 394 | 358 | |
|---|
| 395 | | -} |
|---|
| 396 | | - |
|---|
| 397 | | -/* Enable clocks and set the controller to HDQ/1W mode */ |
|---|
| 398 | | -static int omap_hdq_get(struct hdq_data *hdq_data) |
|---|
| 399 | | -{ |
|---|
| 400 | | - int ret = 0; |
|---|
| 401 | | - |
|---|
| 402 | | - ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); |
|---|
| 403 | | - if (ret < 0) { |
|---|
| 404 | | - ret = -EINTR; |
|---|
| 405 | | - goto rtn; |
|---|
| 406 | | - } |
|---|
| 407 | | - |
|---|
| 408 | | - if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) { |
|---|
| 409 | | - dev_dbg(hdq_data->dev, "attempt to exceed the max use count"); |
|---|
| 410 | | - ret = -EINVAL; |
|---|
| 411 | | - goto out; |
|---|
| 412 | | - } else { |
|---|
| 413 | | - hdq_data->hdq_usecount++; |
|---|
| 414 | | - try_module_get(THIS_MODULE); |
|---|
| 415 | | - if (1 == hdq_data->hdq_usecount) { |
|---|
| 416 | | - |
|---|
| 417 | | - pm_runtime_get_sync(hdq_data->dev); |
|---|
| 418 | | - |
|---|
| 419 | | - /* make sure HDQ/1W is out of reset */ |
|---|
| 420 | | - if (!(hdq_reg_in(hdq_data, OMAP_HDQ_SYSSTATUS) & |
|---|
| 421 | | - OMAP_HDQ_SYSSTATUS_RESETDONE)) { |
|---|
| 422 | | - ret = _omap_hdq_reset(hdq_data); |
|---|
| 423 | | - if (ret) |
|---|
| 424 | | - /* back up the count */ |
|---|
| 425 | | - hdq_data->hdq_usecount--; |
|---|
| 426 | | - } else { |
|---|
| 427 | | - /* select HDQ/1W mode & enable clocks */ |
|---|
| 428 | | - hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS, |
|---|
| 429 | | - OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | |
|---|
| 430 | | - OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK | |
|---|
| 431 | | - hdq_data->mode); |
|---|
| 432 | | - hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, |
|---|
| 433 | | - OMAP_HDQ_SYSCONFIG_NOIDLE); |
|---|
| 434 | | - hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS); |
|---|
| 435 | | - } |
|---|
| 436 | | - } |
|---|
| 437 | | - } |
|---|
| 438 | | - |
|---|
| 439 | | -out: |
|---|
| 440 | | - mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 441 | | -rtn: |
|---|
| 442 | | - return ret; |
|---|
| 443 | | -} |
|---|
| 444 | | - |
|---|
| 445 | | -/* Disable clocks to the module */ |
|---|
| 446 | | -static int omap_hdq_put(struct hdq_data *hdq_data) |
|---|
| 447 | | -{ |
|---|
| 448 | | - int ret = 0; |
|---|
| 449 | | - |
|---|
| 450 | | - ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); |
|---|
| 451 | | - if (ret < 0) |
|---|
| 452 | | - return -EINTR; |
|---|
| 453 | | - |
|---|
| 454 | | - hdq_reg_out(hdq_data, OMAP_HDQ_SYSCONFIG, |
|---|
| 455 | | - OMAP_HDQ_SYSCONFIG_AUTOIDLE); |
|---|
| 456 | | - if (0 == hdq_data->hdq_usecount) { |
|---|
| 457 | | - dev_dbg(hdq_data->dev, "attempt to decrement use count" |
|---|
| 458 | | - " when it is zero"); |
|---|
| 459 | | - ret = -EINVAL; |
|---|
| 460 | | - } else { |
|---|
| 461 | | - hdq_data->hdq_usecount--; |
|---|
| 462 | | - module_put(THIS_MODULE); |
|---|
| 463 | | - if (0 == hdq_data->hdq_usecount) |
|---|
| 464 | | - pm_runtime_put_sync(hdq_data->dev); |
|---|
| 465 | | - } |
|---|
| 466 | | - mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 467 | | - |
|---|
| 468 | | - return ret; |
|---|
| 469 | 359 | } |
|---|
| 470 | 360 | |
|---|
| 471 | 361 | /* |
|---|
| .. | .. |
|---|
| 482 | 372 | OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK; |
|---|
| 483 | 373 | u8 mask = ctrl | OMAP_HDQ_CTRL_STATUS_DIR; |
|---|
| 484 | 374 | |
|---|
| 485 | | - omap_hdq_get(_hdq); |
|---|
| 375 | + err = pm_runtime_get_sync(hdq_data->dev); |
|---|
| 376 | + if (err < 0) { |
|---|
| 377 | + pm_runtime_put_noidle(hdq_data->dev); |
|---|
| 378 | + |
|---|
| 379 | + return err; |
|---|
| 380 | + } |
|---|
| 486 | 381 | |
|---|
| 487 | 382 | err = mutex_lock_interruptible(&hdq_data->hdq_mutex); |
|---|
| 488 | 383 | if (err < 0) { |
|---|
| .. | .. |
|---|
| 490 | 385 | goto rtn; |
|---|
| 491 | 386 | } |
|---|
| 492 | 387 | |
|---|
| 493 | | - hdq_data->hdq_irqstatus = 0; |
|---|
| 494 | 388 | /* read id_bit */ |
|---|
| 495 | 389 | hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, |
|---|
| 496 | 390 | ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask); |
|---|
| .. | .. |
|---|
| 498 | 392 | (hdq_data->hdq_irqstatus |
|---|
| 499 | 393 | & OMAP_HDQ_INT_STATUS_RXCOMPLETE), |
|---|
| 500 | 394 | OMAP_HDQ_TIMEOUT); |
|---|
| 395 | + /* Must clear irqstatus for another RXCOMPLETE interrupt */ |
|---|
| 396 | + hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_RXCOMPLETE); |
|---|
| 397 | + |
|---|
| 501 | 398 | if (err == 0) { |
|---|
| 502 | 399 | dev_dbg(hdq_data->dev, "RX wait elapsed\n"); |
|---|
| 503 | 400 | goto out; |
|---|
| 504 | 401 | } |
|---|
| 505 | 402 | id_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01); |
|---|
| 506 | 403 | |
|---|
| 507 | | - hdq_data->hdq_irqstatus = 0; |
|---|
| 508 | 404 | /* read comp_bit */ |
|---|
| 509 | 405 | hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, |
|---|
| 510 | 406 | ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask); |
|---|
| .. | .. |
|---|
| 512 | 408 | (hdq_data->hdq_irqstatus |
|---|
| 513 | 409 | & OMAP_HDQ_INT_STATUS_RXCOMPLETE), |
|---|
| 514 | 410 | OMAP_HDQ_TIMEOUT); |
|---|
| 411 | + /* Must clear irqstatus for another RXCOMPLETE interrupt */ |
|---|
| 412 | + hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_RXCOMPLETE); |
|---|
| 413 | + |
|---|
| 515 | 414 | if (err == 0) { |
|---|
| 516 | 415 | dev_dbg(hdq_data->dev, "RX wait elapsed\n"); |
|---|
| 517 | 416 | goto out; |
|---|
| .. | .. |
|---|
| 538 | 437 | (hdq_data->hdq_irqstatus |
|---|
| 539 | 438 | & OMAP_HDQ_INT_STATUS_TXCOMPLETE), |
|---|
| 540 | 439 | OMAP_HDQ_TIMEOUT); |
|---|
| 440 | + /* Must clear irqstatus for another TXCOMPLETE interrupt */ |
|---|
| 441 | + hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_TXCOMPLETE); |
|---|
| 442 | + |
|---|
| 541 | 443 | if (err == 0) { |
|---|
| 542 | 444 | dev_dbg(hdq_data->dev, "TX wait elapsed\n"); |
|---|
| 543 | 445 | goto out; |
|---|
| .. | .. |
|---|
| 549 | 451 | out: |
|---|
| 550 | 452 | mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 551 | 453 | rtn: |
|---|
| 552 | | - omap_hdq_put(_hdq); |
|---|
| 454 | + pm_runtime_mark_last_busy(hdq_data->dev); |
|---|
| 455 | + pm_runtime_put_autosuspend(hdq_data->dev); |
|---|
| 456 | + |
|---|
| 553 | 457 | return ret; |
|---|
| 554 | 458 | } |
|---|
| 555 | 459 | |
|---|
| 556 | 460 | /* reset callback */ |
|---|
| 557 | 461 | static u8 omap_w1_reset_bus(void *_hdq) |
|---|
| 558 | 462 | { |
|---|
| 559 | | - omap_hdq_get(_hdq); |
|---|
| 560 | | - omap_hdq_break(_hdq); |
|---|
| 561 | | - omap_hdq_put(_hdq); |
|---|
| 463 | + struct hdq_data *hdq_data = _hdq; |
|---|
| 464 | + int err; |
|---|
| 465 | + |
|---|
| 466 | + err = pm_runtime_get_sync(hdq_data->dev); |
|---|
| 467 | + if (err < 0) { |
|---|
| 468 | + pm_runtime_put_noidle(hdq_data->dev); |
|---|
| 469 | + |
|---|
| 470 | + return err; |
|---|
| 471 | + } |
|---|
| 472 | + |
|---|
| 473 | + omap_hdq_break(hdq_data); |
|---|
| 474 | + |
|---|
| 475 | + pm_runtime_mark_last_busy(hdq_data->dev); |
|---|
| 476 | + pm_runtime_put_autosuspend(hdq_data->dev); |
|---|
| 477 | + |
|---|
| 562 | 478 | return 0; |
|---|
| 563 | 479 | } |
|---|
| 564 | 480 | |
|---|
| .. | .. |
|---|
| 569 | 485 | u8 val = 0; |
|---|
| 570 | 486 | int ret; |
|---|
| 571 | 487 | |
|---|
| 572 | | - /* First write to initialize the transfer */ |
|---|
| 573 | | - if (hdq_data->init_trans == 0) |
|---|
| 574 | | - omap_hdq_get(hdq_data); |
|---|
| 488 | + ret = pm_runtime_get_sync(hdq_data->dev); |
|---|
| 489 | + if (ret < 0) { |
|---|
| 490 | + pm_runtime_put_noidle(hdq_data->dev); |
|---|
| 575 | 491 | |
|---|
| 576 | | - ret = hdq_read_byte(hdq_data, &val); |
|---|
| 577 | | - if (ret) { |
|---|
| 578 | | - ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); |
|---|
| 579 | | - if (ret < 0) { |
|---|
| 580 | | - dev_dbg(hdq_data->dev, "Could not acquire mutex\n"); |
|---|
| 581 | | - return -EINTR; |
|---|
| 582 | | - } |
|---|
| 583 | | - hdq_data->init_trans = 0; |
|---|
| 584 | | - mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 585 | | - omap_hdq_put(hdq_data); |
|---|
| 586 | 492 | return -1; |
|---|
| 587 | 493 | } |
|---|
| 588 | 494 | |
|---|
| 589 | | - hdq_disable_interrupt(hdq_data, OMAP_HDQ_CTRL_STATUS, |
|---|
| 590 | | - ~OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK); |
|---|
| 495 | + ret = hdq_read_byte(hdq_data, &val); |
|---|
| 496 | + if (ret) |
|---|
| 497 | + val = -1; |
|---|
| 591 | 498 | |
|---|
| 592 | | - /* Write followed by a read, release the module */ |
|---|
| 593 | | - if (hdq_data->init_trans) { |
|---|
| 594 | | - ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); |
|---|
| 595 | | - if (ret < 0) { |
|---|
| 596 | | - dev_dbg(hdq_data->dev, "Could not acquire mutex\n"); |
|---|
| 597 | | - return -EINTR; |
|---|
| 598 | | - } |
|---|
| 599 | | - hdq_data->init_trans = 0; |
|---|
| 600 | | - mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 601 | | - omap_hdq_put(hdq_data); |
|---|
| 602 | | - } |
|---|
| 499 | + pm_runtime_mark_last_busy(hdq_data->dev); |
|---|
| 500 | + pm_runtime_put_autosuspend(hdq_data->dev); |
|---|
| 603 | 501 | |
|---|
| 604 | 502 | return val; |
|---|
| 605 | 503 | } |
|---|
| .. | .. |
|---|
| 611 | 509 | int ret; |
|---|
| 612 | 510 | u8 status; |
|---|
| 613 | 511 | |
|---|
| 614 | | - /* First write to initialize the transfer */ |
|---|
| 615 | | - if (hdq_data->init_trans == 0) |
|---|
| 616 | | - omap_hdq_get(hdq_data); |
|---|
| 512 | + ret = pm_runtime_get_sync(hdq_data->dev); |
|---|
| 513 | + if (ret < 0) { |
|---|
| 514 | + pm_runtime_put_noidle(hdq_data->dev); |
|---|
| 515 | + |
|---|
| 516 | + return; |
|---|
| 517 | + } |
|---|
| 617 | 518 | |
|---|
| 618 | 519 | /* |
|---|
| 619 | 520 | * We need to reset the slave before |
|---|
| .. | .. |
|---|
| 623 | 524 | if (byte == W1_SKIP_ROM) |
|---|
| 624 | 525 | omap_hdq_break(hdq_data); |
|---|
| 625 | 526 | |
|---|
| 626 | | - ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); |
|---|
| 627 | | - if (ret < 0) { |
|---|
| 628 | | - dev_dbg(hdq_data->dev, "Could not acquire mutex\n"); |
|---|
| 629 | | - return; |
|---|
| 630 | | - } |
|---|
| 631 | | - hdq_data->init_trans++; |
|---|
| 632 | | - mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 633 | | - |
|---|
| 634 | 527 | ret = hdq_write_byte(hdq_data, byte, &status); |
|---|
| 635 | 528 | if (ret < 0) { |
|---|
| 636 | 529 | dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status); |
|---|
| 637 | | - return; |
|---|
| 530 | + goto out_err; |
|---|
| 638 | 531 | } |
|---|
| 639 | 532 | |
|---|
| 640 | | - /* Second write, data transferred. Release the module */ |
|---|
| 641 | | - if (hdq_data->init_trans > 1) { |
|---|
| 642 | | - omap_hdq_put(hdq_data); |
|---|
| 643 | | - ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); |
|---|
| 644 | | - if (ret < 0) { |
|---|
| 645 | | - dev_dbg(hdq_data->dev, "Could not acquire mutex\n"); |
|---|
| 646 | | - return; |
|---|
| 647 | | - } |
|---|
| 648 | | - hdq_data->init_trans = 0; |
|---|
| 649 | | - mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 650 | | - } |
|---|
| 533 | +out_err: |
|---|
| 534 | + pm_runtime_mark_last_busy(hdq_data->dev); |
|---|
| 535 | + pm_runtime_put_autosuspend(hdq_data->dev); |
|---|
| 651 | 536 | } |
|---|
| 652 | 537 | |
|---|
| 653 | 538 | static struct w1_bus_master omap_w1_master = { |
|---|
| .. | .. |
|---|
| 656 | 541 | .reset_bus = omap_w1_reset_bus, |
|---|
| 657 | 542 | }; |
|---|
| 658 | 543 | |
|---|
| 544 | +static int __maybe_unused omap_hdq_runtime_suspend(struct device *dev) |
|---|
| 545 | +{ |
|---|
| 546 | + struct hdq_data *hdq_data = dev_get_drvdata(dev); |
|---|
| 547 | + |
|---|
| 548 | + hdq_reg_out(hdq_data, 0, hdq_data->mode); |
|---|
| 549 | + hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS); |
|---|
| 550 | + |
|---|
| 551 | + return 0; |
|---|
| 552 | +} |
|---|
| 553 | + |
|---|
| 554 | +static int __maybe_unused omap_hdq_runtime_resume(struct device *dev) |
|---|
| 555 | +{ |
|---|
| 556 | + struct hdq_data *hdq_data = dev_get_drvdata(dev); |
|---|
| 557 | + |
|---|
| 558 | + /* select HDQ/1W mode & enable clocks */ |
|---|
| 559 | + hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS, |
|---|
| 560 | + OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | |
|---|
| 561 | + OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK | |
|---|
| 562 | + hdq_data->mode); |
|---|
| 563 | + hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS); |
|---|
| 564 | + |
|---|
| 565 | + return 0; |
|---|
| 566 | +} |
|---|
| 567 | + |
|---|
| 568 | +static const struct dev_pm_ops omap_hdq_pm_ops = { |
|---|
| 569 | + SET_RUNTIME_PM_OPS(omap_hdq_runtime_suspend, |
|---|
| 570 | + omap_hdq_runtime_resume, NULL) |
|---|
| 571 | +}; |
|---|
| 572 | + |
|---|
| 659 | 573 | static int omap_hdq_probe(struct platform_device *pdev) |
|---|
| 660 | 574 | { |
|---|
| 661 | 575 | struct device *dev = &pdev->dev; |
|---|
| 662 | 576 | struct hdq_data *hdq_data; |
|---|
| 663 | | - struct resource *res; |
|---|
| 664 | 577 | int ret, irq; |
|---|
| 665 | 578 | u8 rev; |
|---|
| 666 | 579 | const char *mode; |
|---|
| .. | .. |
|---|
| 674 | 587 | hdq_data->dev = dev; |
|---|
| 675 | 588 | platform_set_drvdata(pdev, hdq_data); |
|---|
| 676 | 589 | |
|---|
| 677 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 678 | | - hdq_data->hdq_base = devm_ioremap_resource(dev, res); |
|---|
| 590 | + hdq_data->hdq_base = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 679 | 591 | if (IS_ERR(hdq_data->hdq_base)) |
|---|
| 680 | 592 | return PTR_ERR(hdq_data->hdq_base); |
|---|
| 681 | 593 | |
|---|
| 682 | | - hdq_data->hdq_usecount = 0; |
|---|
| 683 | | - hdq_data->rrw = 0; |
|---|
| 684 | 594 | mutex_init(&hdq_data->hdq_mutex); |
|---|
| 685 | 595 | |
|---|
| 686 | | - pm_runtime_enable(&pdev->dev); |
|---|
| 687 | | - ret = pm_runtime_get_sync(&pdev->dev); |
|---|
| 688 | | - if (ret < 0) { |
|---|
| 689 | | - dev_dbg(&pdev->dev, "pm_runtime_get_sync failed\n"); |
|---|
| 690 | | - goto err_w1; |
|---|
| 596 | + ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode); |
|---|
| 597 | + if (ret < 0 || !strcmp(mode, "hdq")) { |
|---|
| 598 | + hdq_data->mode = 0; |
|---|
| 599 | + omap_w1_master.search = omap_w1_search_bus; |
|---|
| 600 | + } else { |
|---|
| 601 | + hdq_data->mode = 1; |
|---|
| 602 | + omap_w1_master.triplet = omap_w1_triplet; |
|---|
| 691 | 603 | } |
|---|
| 692 | 604 | |
|---|
| 693 | | - ret = _omap_hdq_reset(hdq_data); |
|---|
| 694 | | - if (ret) { |
|---|
| 695 | | - dev_dbg(&pdev->dev, "reset failed\n"); |
|---|
| 696 | | - goto err_irq; |
|---|
| 605 | + pm_runtime_enable(&pdev->dev); |
|---|
| 606 | + pm_runtime_use_autosuspend(&pdev->dev); |
|---|
| 607 | + pm_runtime_set_autosuspend_delay(&pdev->dev, 300); |
|---|
| 608 | + ret = pm_runtime_get_sync(&pdev->dev); |
|---|
| 609 | + if (ret < 0) { |
|---|
| 610 | + pm_runtime_put_noidle(&pdev->dev); |
|---|
| 611 | + dev_dbg(&pdev->dev, "pm_runtime_get_sync failed\n"); |
|---|
| 612 | + goto err_w1; |
|---|
| 697 | 613 | } |
|---|
| 698 | 614 | |
|---|
| 699 | 615 | rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION); |
|---|
| .. | .. |
|---|
| 717 | 633 | |
|---|
| 718 | 634 | omap_hdq_break(hdq_data); |
|---|
| 719 | 635 | |
|---|
| 720 | | - pm_runtime_put_sync(&pdev->dev); |
|---|
| 721 | | - |
|---|
| 722 | | - ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode); |
|---|
| 723 | | - if (ret < 0 || !strcmp(mode, "hdq")) { |
|---|
| 724 | | - hdq_data->mode = 0; |
|---|
| 725 | | - omap_w1_master.search = omap_w1_search_bus; |
|---|
| 726 | | - } else { |
|---|
| 727 | | - hdq_data->mode = 1; |
|---|
| 728 | | - omap_w1_master.triplet = omap_w1_triplet; |
|---|
| 729 | | - } |
|---|
| 636 | + pm_runtime_mark_last_busy(&pdev->dev); |
|---|
| 637 | + pm_runtime_put_autosuspend(&pdev->dev); |
|---|
| 730 | 638 | |
|---|
| 731 | 639 | omap_w1_master.data = hdq_data; |
|---|
| 732 | 640 | |
|---|
| .. | .. |
|---|
| 741 | 649 | err_irq: |
|---|
| 742 | 650 | pm_runtime_put_sync(&pdev->dev); |
|---|
| 743 | 651 | err_w1: |
|---|
| 652 | + pm_runtime_dont_use_autosuspend(&pdev->dev); |
|---|
| 744 | 653 | pm_runtime_disable(&pdev->dev); |
|---|
| 745 | 654 | |
|---|
| 746 | 655 | return ret; |
|---|
| .. | .. |
|---|
| 748 | 657 | |
|---|
| 749 | 658 | static int omap_hdq_remove(struct platform_device *pdev) |
|---|
| 750 | 659 | { |
|---|
| 751 | | - struct hdq_data *hdq_data = platform_get_drvdata(pdev); |
|---|
| 660 | + int active; |
|---|
| 752 | 661 | |
|---|
| 753 | | - mutex_lock(&hdq_data->hdq_mutex); |
|---|
| 754 | | - |
|---|
| 755 | | - if (hdq_data->hdq_usecount) { |
|---|
| 756 | | - dev_dbg(&pdev->dev, "removed when use count is not zero\n"); |
|---|
| 757 | | - mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 758 | | - return -EBUSY; |
|---|
| 759 | | - } |
|---|
| 760 | | - |
|---|
| 761 | | - mutex_unlock(&hdq_data->hdq_mutex); |
|---|
| 762 | | - |
|---|
| 763 | | - /* remove module dependency */ |
|---|
| 764 | | - pm_runtime_disable(&pdev->dev); |
|---|
| 662 | + active = pm_runtime_get_sync(&pdev->dev); |
|---|
| 663 | + if (active < 0) |
|---|
| 664 | + pm_runtime_put_noidle(&pdev->dev); |
|---|
| 765 | 665 | |
|---|
| 766 | 666 | w1_remove_master_device(&omap_w1_master); |
|---|
| 667 | + |
|---|
| 668 | + pm_runtime_dont_use_autosuspend(&pdev->dev); |
|---|
| 669 | + if (active >= 0) |
|---|
| 670 | + pm_runtime_put_sync(&pdev->dev); |
|---|
| 671 | + pm_runtime_disable(&pdev->dev); |
|---|
| 767 | 672 | |
|---|
| 768 | 673 | return 0; |
|---|
| 769 | 674 | } |
|---|
| .. | .. |
|---|
| 781 | 686 | .driver = { |
|---|
| 782 | 687 | .name = "omap_hdq", |
|---|
| 783 | 688 | .of_match_table = omap_hdq_dt_ids, |
|---|
| 689 | + .pm = &omap_hdq_pm_ops, |
|---|
| 784 | 690 | }, |
|---|
| 785 | 691 | }; |
|---|
| 786 | 692 | module_platform_driver(omap_hdq_driver); |
|---|