lm78_isa.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /* $OpenBSD: lm78_isa.c,v 1.10 2015/03/14 03:38:47 jsg Exp $ */
  2. /*
  3. * Copyright (c) 2005, 2006 Mark Kettenis
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/param.h>
  18. #include <sys/systm.h>
  19. #include <sys/device.h>
  20. #include <sys/sensors.h>
  21. #include <machine/bus.h>
  22. #include <dev/isa/isavar.h>
  23. #include <dev/ic/lm78var.h>
  24. /* ISA registers */
  25. #define LMC_ADDR 0x05
  26. #define LMC_DATA 0x06
  27. extern struct cfdriver lm_cd;
  28. #if defined(LMDEBUG)
  29. #define DPRINTF(x) do { printf x; } while (0)
  30. #else
  31. #define DPRINTF(x)
  32. #endif
  33. struct lm_isa_softc {
  34. struct lm_softc sc_lmsc;
  35. bus_space_tag_t sc_iot;
  36. bus_space_handle_t sc_ioh;
  37. };
  38. int lm_isa_match(struct device *, void *, void *);
  39. int lm_wbsio_match(struct device *, void *, void *);
  40. void lm_isa_attach(struct device *, struct device *, void *);
  41. u_int8_t lm_isa_readreg(struct lm_softc *, int);
  42. void lm_isa_writereg(struct lm_softc *, int, int);
  43. void lm_isa_remove_alias(struct lm_softc *, const char *);
  44. struct cfattach lm_isa_ca = {
  45. sizeof(struct lm_isa_softc),
  46. lm_isa_match,
  47. lm_isa_attach
  48. };
  49. struct cfattach lm_wbsio_ca = {
  50. sizeof(struct lm_isa_softc),
  51. lm_wbsio_match,
  52. lm_isa_attach
  53. };
  54. int
  55. lm_wbsio_match(struct device *parent, void *match, void *aux)
  56. {
  57. bus_space_tag_t iot;
  58. bus_addr_t iobase;
  59. bus_space_handle_t ioh;
  60. struct isa_attach_args *ia = aux;
  61. int banksel, vendid;
  62. iot = ia->ia_iot;
  63. iobase = ia->ipa_io[0].base;
  64. if (bus_space_map(iot, iobase, 8, 0, &ioh)) {
  65. DPRINTF(("%s: can't map i/o space\n", __func__));
  66. return (0);
  67. }
  68. /* Probe for Winbond chips. */
  69. bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
  70. banksel = bus_space_read_1(iot, ioh, LMC_DATA);
  71. bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
  72. bus_space_write_1(iot, ioh, LMC_DATA, WB_BANKSEL_HBAC);
  73. bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID);
  74. vendid = bus_space_read_1(iot, ioh, LMC_DATA) << 8;
  75. bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
  76. bus_space_write_1(iot, ioh, LMC_DATA, 0);
  77. bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID);
  78. vendid |= bus_space_read_1(iot, ioh, LMC_DATA);
  79. bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
  80. bus_space_write_1(iot, ioh, LMC_DATA, banksel);
  81. bus_space_unmap(iot, ioh, 8);
  82. if (vendid != WB_VENDID_WINBOND)
  83. return (0);
  84. ia->ipa_nio = 1;
  85. ia->ipa_io[0].length = 8;
  86. ia->ipa_nmem = 0;
  87. ia->ipa_nirq = 0;
  88. ia->ipa_ndrq = 0;
  89. return (1);
  90. }
  91. int
  92. lm_isa_match(struct device *parent, void *match, void *aux)
  93. {
  94. bus_space_tag_t iot;
  95. bus_addr_t iobase;
  96. bus_space_handle_t ioh;
  97. struct isa_attach_args *ia = aux;
  98. int banksel, vendid, chipid, addr;
  99. iot = ia->ia_iot;
  100. iobase = ia->ipa_io[0].base;
  101. if (bus_space_map(iot, iobase, 8, 0, &ioh)) {
  102. DPRINTF(("%s: can't map i/o space\n", __func__));
  103. return (0);
  104. }
  105. /* Probe for Winbond chips. */
  106. bus_space_write_1(iot, ioh, LMC_ADDR, WB_BANKSEL);
  107. banksel = bus_space_read_1(iot, ioh, LMC_DATA);
  108. bus_space_write_1(iot, ioh, LMC_ADDR, WB_VENDID);
  109. vendid = bus_space_read_1(iot, ioh, LMC_DATA);
  110. if (((banksel & 0x80) && vendid == (WB_VENDID_WINBOND >> 8)) ||
  111. (!(banksel & 0x80) && vendid == (WB_VENDID_WINBOND & 0xff)))
  112. goto found;
  113. /* Probe for ITE chips (and don't attach if we find one). */
  114. bus_space_write_1(iot, ioh, LMC_ADDR, 0x58);
  115. if ((vendid = bus_space_read_1(iot, ioh, LMC_DATA)) == 0x90)
  116. goto notfound;
  117. /*
  118. * Probe for National Semiconductor LM78/79/81.
  119. *
  120. * XXX This assumes the address has not been changed from the
  121. * power up default. This is probably a reasonable
  122. * assumption, and if it isn't true, we should be able to
  123. * access the chip using the serial bus.
  124. */
  125. bus_space_write_1(iot, ioh, LMC_ADDR, LM_SBUSADDR);
  126. addr = bus_space_read_1(iot, ioh, LMC_DATA);
  127. if ((addr & 0xfc) == 0x2c) {
  128. bus_space_write_1(iot, ioh, LMC_ADDR, LM_CHIPID);
  129. chipid = bus_space_read_1(iot, ioh, LMC_DATA);
  130. switch (chipid & LM_CHIPID_MASK) {
  131. case LM_CHIPID_LM78:
  132. case LM_CHIPID_LM78J:
  133. case LM_CHIPID_LM79:
  134. case LM_CHIPID_LM81:
  135. goto found;
  136. }
  137. }
  138. notfound:
  139. bus_space_unmap(iot, ioh, 8);
  140. return (0);
  141. found:
  142. bus_space_unmap(iot, ioh, 8);
  143. ia->ipa_nio = 1;
  144. ia->ipa_io[0].length = 8;
  145. ia->ipa_nmem = 0;
  146. ia->ipa_nirq = 0;
  147. ia->ipa_ndrq = 0;
  148. return (1);
  149. }
  150. void
  151. lm_isa_attach(struct device *parent, struct device *self, void *aux)
  152. {
  153. struct lm_isa_softc *sc = (struct lm_isa_softc *)self;
  154. struct isa_attach_args *ia = aux;
  155. struct lm_softc *lmsc;
  156. bus_addr_t iobase;
  157. int i;
  158. u_int8_t sbusaddr;
  159. sc->sc_iot = ia->ia_iot;
  160. iobase = ia->ipa_io[0].base;
  161. if (bus_space_map(sc->sc_iot, iobase, 8, 0, &sc->sc_ioh)) {
  162. printf(": can't map i/o space\n");
  163. return;
  164. }
  165. /* Bus-independant attachment */
  166. sc->sc_lmsc.lm_writereg = lm_isa_writereg;
  167. sc->sc_lmsc.lm_readreg = lm_isa_readreg;
  168. /* pass through wbsio(4) devid */
  169. if (ia->ia_aux)
  170. sc->sc_lmsc.sioid = (u_int8_t)(u_long)ia->ia_aux;
  171. lm_attach(&sc->sc_lmsc);
  172. /*
  173. * Most devices supported by this driver can attach to iic(4)
  174. * as well. However, we prefer to attach them to isa(4) since
  175. * that causes less overhead and is more reliable. We look
  176. * through all previously attached devices, and if we find an
  177. * identical chip at the same serial bus address, we stop
  178. * updating its sensors and mark them as invalid.
  179. */
  180. sbusaddr = lm_isa_readreg(&sc->sc_lmsc, LM_SBUSADDR);
  181. if (sbusaddr == 0)
  182. return;
  183. for (i = 0; i < lm_cd.cd_ndevs; i++) {
  184. lmsc = lm_cd.cd_devs[i];
  185. if (lmsc == &sc->sc_lmsc)
  186. continue;
  187. if (lmsc && lmsc->sbusaddr == sbusaddr &&
  188. lmsc->chipid == sc->sc_lmsc.chipid) {
  189. lm_isa_remove_alias(lmsc, sc->sc_lmsc.sc_dev.dv_xname);
  190. break;
  191. }
  192. }
  193. }
  194. /* Remove sensors of the i2c alias, since we prefer to use the isa access */
  195. void
  196. lm_isa_remove_alias(struct lm_softc *sc, const char *isa)
  197. {
  198. int i;
  199. printf("%s: disabling sensors due to alias with %s\n",
  200. sc->sc_dev.dv_xname, isa);
  201. sensordev_deinstall(&sc->sensordev);
  202. for (i = 0; i < sc->numsensors; i++)
  203. sensor_detach(&sc->sensordev, &sc->sensors[i]);
  204. if (sc->sensortask != NULL)
  205. sensor_task_unregister(sc->sensortask);
  206. sc->sensortask = NULL;
  207. }
  208. u_int8_t
  209. lm_isa_readreg(struct lm_softc *lmsc, int reg)
  210. {
  211. struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
  212. bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
  213. return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, LMC_DATA));
  214. }
  215. void
  216. lm_isa_writereg(struct lm_softc *lmsc, int reg, int val)
  217. {
  218. struct lm_isa_softc *sc = (struct lm_isa_softc *)lmsc;
  219. bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_ADDR, reg);
  220. bus_space_write_1(sc->sc_iot, sc->sc_ioh, LMC_DATA, val);
  221. }