i2sbus-control.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * i2sbus driver -- bus control routines
  3. *
  4. * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
  5. *
  6. * GPL v2, can be found in COPYING.
  7. */
  8. #include <asm/io.h>
  9. #include <linux/delay.h>
  10. #include <asm/prom.h>
  11. #include <asm/macio.h>
  12. #include <asm/pmac_feature.h>
  13. #include <asm/pmac_pfunc.h>
  14. #include "i2sbus.h"
  15. int i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c)
  16. {
  17. *c = kzalloc(sizeof(struct i2sbus_control), GFP_KERNEL);
  18. if (!*c)
  19. return -ENOMEM;
  20. INIT_LIST_HEAD(&(*c)->list);
  21. if (of_address_to_resource(dev->ofdev.node, 0, &(*c)->rsrc))
  22. goto err;
  23. /* we really should be using feature calls instead of mapping
  24. * these registers. It's safe for now since no one else is
  25. * touching them... */
  26. (*c)->controlregs = ioremap((*c)->rsrc.start,
  27. sizeof(struct i2s_control_regs));
  28. if (!(*c)->controlregs)
  29. goto err;
  30. return 0;
  31. err:
  32. kfree(*c);
  33. *c = NULL;
  34. return -ENODEV;
  35. }
  36. void i2sbus_control_destroy(struct i2sbus_control *c)
  37. {
  38. iounmap(c->controlregs);
  39. kfree(c);
  40. }
  41. /* this is serialised externally */
  42. int i2sbus_control_add_dev(struct i2sbus_control *c,
  43. struct i2sbus_dev *i2sdev)
  44. {
  45. struct device_node *np;
  46. np = i2sdev->sound.ofdev.node;
  47. i2sdev->enable = pmf_find_function(np, "enable");
  48. i2sdev->cell_enable = pmf_find_function(np, "cell-enable");
  49. i2sdev->clock_enable = pmf_find_function(np, "clock-enable");
  50. i2sdev->cell_disable = pmf_find_function(np, "cell-disable");
  51. i2sdev->clock_disable = pmf_find_function(np, "clock-disable");
  52. /* if the bus number is not 0 or 1 we absolutely need to use
  53. * the platform functions -- there's nothing in Darwin that
  54. * would allow seeing a system behind what the FCRs are then,
  55. * and I don't want to go parsing a bunch of platform functions
  56. * by hand to try finding a system... */
  57. if (i2sdev->bus_number != 0 && i2sdev->bus_number != 1 &&
  58. (!i2sdev->enable ||
  59. !i2sdev->cell_enable || !i2sdev->clock_enable ||
  60. !i2sdev->cell_disable || !i2sdev->clock_disable)) {
  61. pmf_put_function(i2sdev->enable);
  62. pmf_put_function(i2sdev->cell_enable);
  63. pmf_put_function(i2sdev->clock_enable);
  64. pmf_put_function(i2sdev->cell_disable);
  65. pmf_put_function(i2sdev->clock_disable);
  66. return -ENODEV;
  67. }
  68. list_add(&i2sdev->item, &c->list);
  69. return 0;
  70. }
  71. void i2sbus_control_remove_dev(struct i2sbus_control *c,
  72. struct i2sbus_dev *i2sdev)
  73. {
  74. /* this is serialised externally */
  75. list_del(&i2sdev->item);
  76. if (list_empty(&c->list))
  77. i2sbus_control_destroy(c);
  78. }
  79. int i2sbus_control_enable(struct i2sbus_control *c,
  80. struct i2sbus_dev *i2sdev)
  81. {
  82. struct pmf_args args = { .count = 0 };
  83. int cc;
  84. if (i2sdev->enable)
  85. return pmf_call_one(i2sdev->enable, &args);
  86. switch (i2sdev->bus_number) {
  87. case 0:
  88. cc = in_le32(&c->controlregs->cell_control);
  89. out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_0_ENABLE);
  90. break;
  91. case 1:
  92. cc = in_le32(&c->controlregs->cell_control);
  93. out_le32(&c->controlregs->cell_control, cc | CTRL_CLOCK_INTF_1_ENABLE);
  94. break;
  95. default:
  96. return -ENODEV;
  97. }
  98. return 0;
  99. }
  100. int i2sbus_control_cell(struct i2sbus_control *c,
  101. struct i2sbus_dev *i2sdev,
  102. int enable)
  103. {
  104. struct pmf_args args = { .count = 0 };
  105. int cc;
  106. switch (enable) {
  107. case 0:
  108. if (i2sdev->cell_disable)
  109. return pmf_call_one(i2sdev->cell_disable, &args);
  110. break;
  111. case 1:
  112. if (i2sdev->cell_enable)
  113. return pmf_call_one(i2sdev->cell_enable, &args);
  114. break;
  115. default:
  116. printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n");
  117. return -ENODEV;
  118. }
  119. switch (i2sdev->bus_number) {
  120. case 0:
  121. cc = in_le32(&c->controlregs->cell_control);
  122. cc &= ~CTRL_CLOCK_CELL_0_ENABLE;
  123. cc |= enable * CTRL_CLOCK_CELL_0_ENABLE;
  124. out_le32(&c->controlregs->cell_control, cc);
  125. break;
  126. case 1:
  127. cc = in_le32(&c->controlregs->cell_control);
  128. cc &= ~CTRL_CLOCK_CELL_1_ENABLE;
  129. cc |= enable * CTRL_CLOCK_CELL_1_ENABLE;
  130. out_le32(&c->controlregs->cell_control, cc);
  131. break;
  132. default:
  133. return -ENODEV;
  134. }
  135. return 0;
  136. }
  137. int i2sbus_control_clock(struct i2sbus_control *c,
  138. struct i2sbus_dev *i2sdev,
  139. int enable)
  140. {
  141. struct pmf_args args = { .count = 0 };
  142. int cc;
  143. switch (enable) {
  144. case 0:
  145. if (i2sdev->clock_disable)
  146. return pmf_call_one(i2sdev->clock_disable, &args);
  147. break;
  148. case 1:
  149. if (i2sdev->clock_enable)
  150. return pmf_call_one(i2sdev->clock_enable, &args);
  151. break;
  152. default:
  153. printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n");
  154. return -ENODEV;
  155. }
  156. switch (i2sdev->bus_number) {
  157. case 0:
  158. cc = in_le32(&c->controlregs->cell_control);
  159. cc &= ~CTRL_CLOCK_CLOCK_0_ENABLE;
  160. cc |= enable * CTRL_CLOCK_CLOCK_0_ENABLE;
  161. out_le32(&c->controlregs->cell_control, cc);
  162. break;
  163. case 1:
  164. cc = in_le32(&c->controlregs->cell_control);
  165. cc &= ~CTRL_CLOCK_CLOCK_1_ENABLE;
  166. cc |= enable * CTRL_CLOCK_CLOCK_1_ENABLE;
  167. out_le32(&c->controlregs->cell_control, cc);
  168. break;
  169. default:
  170. return -ENODEV;
  171. }
  172. return 0;
  173. }