encx24j600-regmap.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. /**
  2. * Register map access API - ENCX24J600 support
  3. *
  4. * Copyright 2015 Gridpoint
  5. *
  6. * Author: Jon Ringle <jringle@gridpoint.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/delay.h>
  13. #include <linux/errno.h>
  14. #include <linux/init.h>
  15. #include <linux/module.h>
  16. #include <linux/netdevice.h>
  17. #include <linux/regmap.h>
  18. #include <linux/spi/spi.h>
  19. #include "encx24j600_hw.h"
  20. static inline bool is_bits_set(int value, int mask)
  21. {
  22. return (value & mask) == mask;
  23. }
  24. static int encx24j600_switch_bank(struct encx24j600_context *ctx,
  25. int bank)
  26. {
  27. int ret = 0;
  28. int bank_opcode = BANK_SELECT(bank);
  29. ret = spi_write(ctx->spi, &bank_opcode, 1);
  30. if (ret == 0)
  31. ctx->bank = bank;
  32. return ret;
  33. }
  34. static int encx24j600_cmdn(struct encx24j600_context *ctx, u8 opcode,
  35. const void *buf, size_t len)
  36. {
  37. struct spi_message m;
  38. struct spi_transfer t[2] = { { .tx_buf = &opcode, .len = 1, },
  39. { .tx_buf = buf, .len = len }, };
  40. spi_message_init(&m);
  41. spi_message_add_tail(&t[0], &m);
  42. spi_message_add_tail(&t[1], &m);
  43. return spi_sync(ctx->spi, &m);
  44. }
  45. static void regmap_lock_mutex(void *context)
  46. {
  47. struct encx24j600_context *ctx = context;
  48. mutex_lock(&ctx->mutex);
  49. }
  50. static void regmap_unlock_mutex(void *context)
  51. {
  52. struct encx24j600_context *ctx = context;
  53. mutex_unlock(&ctx->mutex);
  54. }
  55. static int regmap_encx24j600_sfr_read(void *context, u8 reg, u8 *val,
  56. size_t len)
  57. {
  58. struct encx24j600_context *ctx = context;
  59. u8 banked_reg = reg & ADDR_MASK;
  60. u8 bank = ((reg & BANK_MASK) >> BANK_SHIFT);
  61. u8 cmd = RCRU;
  62. int ret = 0;
  63. int i = 0;
  64. u8 tx_buf[2];
  65. if (reg < 0x80) {
  66. cmd = RCRCODE | banked_reg;
  67. if ((banked_reg < 0x16) && (ctx->bank != bank))
  68. ret = encx24j600_switch_bank(ctx, bank);
  69. if (unlikely(ret))
  70. return ret;
  71. } else {
  72. /* Translate registers that are more effecient using
  73. * 3-byte SPI commands
  74. */
  75. switch (reg) {
  76. case EGPRDPT:
  77. cmd = RGPRDPT; break;
  78. case EGPWRPT:
  79. cmd = RGPWRPT; break;
  80. case ERXRDPT:
  81. cmd = RRXRDPT; break;
  82. case ERXWRPT:
  83. cmd = RRXWRPT; break;
  84. case EUDARDPT:
  85. cmd = RUDARDPT; break;
  86. case EUDAWRPT:
  87. cmd = RUDAWRPT; break;
  88. case EGPDATA:
  89. case ERXDATA:
  90. case EUDADATA:
  91. default:
  92. return -EINVAL;
  93. }
  94. }
  95. tx_buf[i++] = cmd;
  96. if (cmd == RCRU)
  97. tx_buf[i++] = reg;
  98. ret = spi_write_then_read(ctx->spi, tx_buf, i, val, len);
  99. return ret;
  100. }
  101. static int regmap_encx24j600_sfr_update(struct encx24j600_context *ctx,
  102. u8 reg, u8 *val, size_t len,
  103. u8 unbanked_cmd, u8 banked_code)
  104. {
  105. u8 banked_reg = reg & ADDR_MASK;
  106. u8 bank = ((reg & BANK_MASK) >> BANK_SHIFT);
  107. u8 cmd = unbanked_cmd;
  108. struct spi_message m;
  109. struct spi_transfer t[3] = { { .tx_buf = &cmd, .len = sizeof(cmd), },
  110. { .tx_buf = &reg, .len = sizeof(reg), },
  111. { .tx_buf = val, .len = len }, };
  112. if (reg < 0x80) {
  113. int ret = 0;
  114. cmd = banked_code | banked_reg;
  115. if ((banked_reg < 0x16) && (ctx->bank != bank))
  116. ret = encx24j600_switch_bank(ctx, bank);
  117. if (unlikely(ret))
  118. return ret;
  119. } else {
  120. /* Translate registers that are more effecient using
  121. * 3-byte SPI commands
  122. */
  123. switch (reg) {
  124. case EGPRDPT:
  125. cmd = WGPRDPT; break;
  126. case EGPWRPT:
  127. cmd = WGPWRPT; break;
  128. case ERXRDPT:
  129. cmd = WRXRDPT; break;
  130. case ERXWRPT:
  131. cmd = WRXWRPT; break;
  132. case EUDARDPT:
  133. cmd = WUDARDPT; break;
  134. case EUDAWRPT:
  135. cmd = WUDAWRPT; break;
  136. case EGPDATA:
  137. case ERXDATA:
  138. case EUDADATA:
  139. default:
  140. return -EINVAL;
  141. }
  142. }
  143. spi_message_init(&m);
  144. spi_message_add_tail(&t[0], &m);
  145. if (cmd == unbanked_cmd) {
  146. t[1].tx_buf = &reg;
  147. spi_message_add_tail(&t[1], &m);
  148. }
  149. spi_message_add_tail(&t[2], &m);
  150. return spi_sync(ctx->spi, &m);
  151. }
  152. static int regmap_encx24j600_sfr_write(void *context, u8 reg, u8 *val,
  153. size_t len)
  154. {
  155. struct encx24j600_context *ctx = context;
  156. return regmap_encx24j600_sfr_update(ctx, reg, val, len, WCRU, WCRCODE);
  157. }
  158. static int regmap_encx24j600_sfr_set_bits(struct encx24j600_context *ctx,
  159. u8 reg, u8 val)
  160. {
  161. return regmap_encx24j600_sfr_update(ctx, reg, &val, 1, BFSU, BFSCODE);
  162. }
  163. static int regmap_encx24j600_sfr_clr_bits(struct encx24j600_context *ctx,
  164. u8 reg, u8 val)
  165. {
  166. return regmap_encx24j600_sfr_update(ctx, reg, &val, 1, BFCU, BFCCODE);
  167. }
  168. static int regmap_encx24j600_reg_update_bits(void *context, unsigned int reg,
  169. unsigned int mask,
  170. unsigned int val)
  171. {
  172. struct encx24j600_context *ctx = context;
  173. int ret = 0;
  174. unsigned int set_mask = mask & val;
  175. unsigned int clr_mask = mask & ~val;
  176. if ((reg >= 0x40 && reg < 0x6c) || reg >= 0x80)
  177. return -EINVAL;
  178. if (set_mask & 0xff)
  179. ret = regmap_encx24j600_sfr_set_bits(ctx, reg, set_mask);
  180. set_mask = (set_mask & 0xff00) >> 8;
  181. if ((set_mask & 0xff) && (ret == 0))
  182. ret = regmap_encx24j600_sfr_set_bits(ctx, reg + 1, set_mask);
  183. if ((clr_mask & 0xff) && (ret == 0))
  184. ret = regmap_encx24j600_sfr_clr_bits(ctx, reg, clr_mask);
  185. clr_mask = (clr_mask & 0xff00) >> 8;
  186. if ((clr_mask & 0xff) && (ret == 0))
  187. ret = regmap_encx24j600_sfr_clr_bits(ctx, reg + 1, clr_mask);
  188. return ret;
  189. }
  190. int regmap_encx24j600_spi_write(void *context, u8 reg, const u8 *data,
  191. size_t count)
  192. {
  193. struct encx24j600_context *ctx = context;
  194. if (reg < 0xc0)
  195. return encx24j600_cmdn(ctx, reg, data, count);
  196. /* SPI 1-byte command. Ignore data */
  197. return spi_write(ctx->spi, &reg, 1);
  198. }
  199. EXPORT_SYMBOL_GPL(regmap_encx24j600_spi_write);
  200. int regmap_encx24j600_spi_read(void *context, u8 reg, u8 *data, size_t count)
  201. {
  202. struct encx24j600_context *ctx = context;
  203. if (reg == RBSEL && count > 1)
  204. count = 1;
  205. return spi_write_then_read(ctx->spi, &reg, sizeof(reg), data, count);
  206. }
  207. EXPORT_SYMBOL_GPL(regmap_encx24j600_spi_read);
  208. static int regmap_encx24j600_write(void *context, const void *data,
  209. size_t len)
  210. {
  211. u8 *dout = (u8 *)data;
  212. u8 reg = dout[0];
  213. ++dout;
  214. --len;
  215. if (reg > 0xa0)
  216. return regmap_encx24j600_spi_write(context, reg, dout, len);
  217. if (len > 2)
  218. return -EINVAL;
  219. return regmap_encx24j600_sfr_write(context, reg, dout, len);
  220. }
  221. static int regmap_encx24j600_read(void *context,
  222. const void *reg_buf, size_t reg_size,
  223. void *val, size_t val_size)
  224. {
  225. u8 reg = *(const u8 *)reg_buf;
  226. if (reg_size != 1) {
  227. pr_err("%s: reg=%02x reg_size=%zu\n", __func__, reg, reg_size);
  228. return -EINVAL;
  229. }
  230. if (reg > 0xa0)
  231. return regmap_encx24j600_spi_read(context, reg, val, val_size);
  232. if (val_size > 2) {
  233. pr_err("%s: reg=%02x val_size=%zu\n", __func__, reg, val_size);
  234. return -EINVAL;
  235. }
  236. return regmap_encx24j600_sfr_read(context, reg, val, val_size);
  237. }
  238. static bool encx24j600_regmap_readable(struct device *dev, unsigned int reg)
  239. {
  240. if ((reg < 0x36) ||
  241. ((reg >= 0x40) && (reg < 0x4c)) ||
  242. ((reg >= 0x52) && (reg < 0x56)) ||
  243. ((reg >= 0x60) && (reg < 0x66)) ||
  244. ((reg >= 0x68) && (reg < 0x80)) ||
  245. ((reg >= 0x86) && (reg < 0x92)) ||
  246. (reg == 0xc8))
  247. return true;
  248. else
  249. return false;
  250. }
  251. static bool encx24j600_regmap_writeable(struct device *dev, unsigned int reg)
  252. {
  253. if ((reg < 0x12) ||
  254. ((reg >= 0x14) && (reg < 0x1a)) ||
  255. ((reg >= 0x1c) && (reg < 0x36)) ||
  256. ((reg >= 0x40) && (reg < 0x4c)) ||
  257. ((reg >= 0x52) && (reg < 0x56)) ||
  258. ((reg >= 0x60) && (reg < 0x68)) ||
  259. ((reg >= 0x6c) && (reg < 0x80)) ||
  260. ((reg >= 0x86) && (reg < 0x92)) ||
  261. ((reg >= 0xc0) && (reg < 0xc8)) ||
  262. ((reg >= 0xca) && (reg < 0xf0)))
  263. return true;
  264. else
  265. return false;
  266. }
  267. static bool encx24j600_regmap_volatile(struct device *dev, unsigned int reg)
  268. {
  269. switch (reg) {
  270. case ERXHEAD:
  271. case EDMACS:
  272. case ETXSTAT:
  273. case ETXWIRE:
  274. case ECON1: /* Can be modified via single byte cmds */
  275. case ECON2: /* Can be modified via single byte cmds */
  276. case ESTAT:
  277. case EIR: /* Can be modified via single byte cmds */
  278. case MIRD:
  279. case MISTAT:
  280. return true;
  281. default:
  282. break;
  283. }
  284. return false;
  285. }
  286. static bool encx24j600_regmap_precious(struct device *dev, unsigned int reg)
  287. {
  288. /* single byte cmds are precious */
  289. if (((reg >= 0xc0) && (reg < 0xc8)) ||
  290. ((reg >= 0xca) && (reg < 0xf0)))
  291. return true;
  292. else
  293. return false;
  294. }
  295. static int regmap_encx24j600_phy_reg_read(void *context, unsigned int reg,
  296. unsigned int *val)
  297. {
  298. struct encx24j600_context *ctx = context;
  299. int ret;
  300. unsigned int mistat;
  301. reg = MIREGADR_VAL | (reg & PHREG_MASK);
  302. ret = regmap_write(ctx->regmap, MIREGADR, reg);
  303. if (unlikely(ret))
  304. goto err_out;
  305. ret = regmap_write(ctx->regmap, MICMD, MIIRD);
  306. if (unlikely(ret))
  307. goto err_out;
  308. usleep_range(26, 100);
  309. while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) &&
  310. (mistat & BUSY))
  311. cpu_relax();
  312. if (unlikely(ret))
  313. goto err_out;
  314. ret = regmap_write(ctx->regmap, MICMD, 0);
  315. if (unlikely(ret))
  316. goto err_out;
  317. ret = regmap_read(ctx->regmap, MIRD, val);
  318. err_out:
  319. if (ret)
  320. pr_err("%s: error %d reading reg %02x\n", __func__, ret,
  321. reg & PHREG_MASK);
  322. return ret;
  323. }
  324. static int regmap_encx24j600_phy_reg_write(void *context, unsigned int reg,
  325. unsigned int val)
  326. {
  327. struct encx24j600_context *ctx = context;
  328. int ret;
  329. unsigned int mistat;
  330. reg = MIREGADR_VAL | (reg & PHREG_MASK);
  331. ret = regmap_write(ctx->regmap, MIREGADR, reg);
  332. if (unlikely(ret))
  333. goto err_out;
  334. ret = regmap_write(ctx->regmap, MIWR, val);
  335. if (unlikely(ret))
  336. goto err_out;
  337. usleep_range(26, 100);
  338. while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) &&
  339. (mistat & BUSY))
  340. cpu_relax();
  341. err_out:
  342. if (ret)
  343. pr_err("%s: error %d writing reg %02x=%04x\n", __func__, ret,
  344. reg & PHREG_MASK, val);
  345. return ret;
  346. }
  347. static bool encx24j600_phymap_readable(struct device *dev, unsigned int reg)
  348. {
  349. switch (reg) {
  350. case PHCON1:
  351. case PHSTAT1:
  352. case PHANA:
  353. case PHANLPA:
  354. case PHANE:
  355. case PHCON2:
  356. case PHSTAT2:
  357. case PHSTAT3:
  358. return true;
  359. default:
  360. return false;
  361. }
  362. }
  363. static bool encx24j600_phymap_writeable(struct device *dev, unsigned int reg)
  364. {
  365. switch (reg) {
  366. case PHCON1:
  367. case PHCON2:
  368. case PHANA:
  369. return true;
  370. case PHSTAT1:
  371. case PHSTAT2:
  372. case PHSTAT3:
  373. case PHANLPA:
  374. case PHANE:
  375. default:
  376. return false;
  377. }
  378. }
  379. static bool encx24j600_phymap_volatile(struct device *dev, unsigned int reg)
  380. {
  381. switch (reg) {
  382. case PHSTAT1:
  383. case PHSTAT2:
  384. case PHSTAT3:
  385. case PHANLPA:
  386. case PHANE:
  387. case PHCON2:
  388. return true;
  389. default:
  390. return false;
  391. }
  392. }
  393. static struct regmap_config regcfg = {
  394. .name = "reg",
  395. .reg_bits = 8,
  396. .val_bits = 16,
  397. .max_register = 0xee,
  398. .reg_stride = 2,
  399. .cache_type = REGCACHE_RBTREE,
  400. .val_format_endian = REGMAP_ENDIAN_LITTLE,
  401. .readable_reg = encx24j600_regmap_readable,
  402. .writeable_reg = encx24j600_regmap_writeable,
  403. .volatile_reg = encx24j600_regmap_volatile,
  404. .precious_reg = encx24j600_regmap_precious,
  405. .lock = regmap_lock_mutex,
  406. .unlock = regmap_unlock_mutex,
  407. };
  408. static struct regmap_bus regmap_encx24j600 = {
  409. .write = regmap_encx24j600_write,
  410. .read = regmap_encx24j600_read,
  411. .reg_update_bits = regmap_encx24j600_reg_update_bits,
  412. };
  413. static struct regmap_config phycfg = {
  414. .name = "phy",
  415. .reg_bits = 8,
  416. .val_bits = 16,
  417. .max_register = 0x1f,
  418. .cache_type = REGCACHE_RBTREE,
  419. .val_format_endian = REGMAP_ENDIAN_LITTLE,
  420. .readable_reg = encx24j600_phymap_readable,
  421. .writeable_reg = encx24j600_phymap_writeable,
  422. .volatile_reg = encx24j600_phymap_volatile,
  423. };
  424. static struct regmap_bus phymap_encx24j600 = {
  425. .reg_write = regmap_encx24j600_phy_reg_write,
  426. .reg_read = regmap_encx24j600_phy_reg_read,
  427. };
  428. void devm_regmap_init_encx24j600(struct device *dev,
  429. struct encx24j600_context *ctx)
  430. {
  431. mutex_init(&ctx->mutex);
  432. regcfg.lock_arg = ctx;
  433. ctx->regmap = devm_regmap_init(dev, &regmap_encx24j600, ctx, &regcfg);
  434. ctx->phymap = devm_regmap_init(dev, &phymap_encx24j600, ctx, &phycfg);
  435. }
  436. EXPORT_SYMBOL_GPL(devm_regmap_init_encx24j600);
  437. MODULE_LICENSE("GPL");