1235537Sgber/*- 2235537Sgber * Copyright (C) 2009-2012 Semihalf 3235537Sgber * All rights reserved. 4235537Sgber * 5235537Sgber * Redistribution and use in source and binary forms, with or without 6235537Sgber * modification, are permitted provided that the following conditions 7235537Sgber * are met: 8235537Sgber * 1. Redistributions of source code must retain the above copyright 9235537Sgber * notice, this list of conditions and the following disclaimer. 10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright 11235537Sgber * notice, this list of conditions and the following disclaimer in the 12235537Sgber * documentation and/or other materials provided with the distribution. 13235537Sgber * 14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235537Sgber * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235537Sgber * SUCH DAMAGE. 25235537Sgber */ 26235537Sgber 27235537Sgber#include <sys/cdefs.h> 28235537Sgber__FBSDID("$FreeBSD$"); 29235537Sgber 30235537Sgber#include <sys/param.h> 31235537Sgber#include <sys/systm.h> 32235537Sgber#include <sys/kernel.h> 33235537Sgber#include <sys/socket.h> 34235537Sgber#include <sys/malloc.h> 35235537Sgber#include <sys/module.h> 36235537Sgber#include <sys/bus.h> 37235537Sgber#include <sys/proc.h> 38235537Sgber#include <sys/lock.h> 39235537Sgber#include <sys/mutex.h> 40235537Sgber#include <sys/condvar.h> 41235537Sgber 42235537Sgber#include <dev/nand/nand.h> 43235537Sgber#include <dev/nand/nandbus.h> 44235537Sgber#include "nand_if.h" 45235537Sgber#include "nandbus_if.h" 46235537Sgber#include "nfc_if.h" 47235537Sgber 48235537Sgber#define NAND_NCS 4 49235537Sgber 50235537Sgberstatic int nandbus_probe(device_t dev); 51235537Sgberstatic int nandbus_attach(device_t dev); 52235537Sgberstatic int nandbus_detach(device_t dev); 53235537Sgber 54235537Sgberstatic int nandbus_child_location_str(device_t, device_t, char *, size_t); 55235537Sgberstatic int nandbus_child_pnpinfo_str(device_t, device_t, char *, size_t); 56235537Sgber 57235537Sgberstatic int nandbus_get_status(device_t, uint8_t *); 58235537Sgberstatic void nandbus_read_buffer(device_t, void *, uint32_t); 59235537Sgberstatic int nandbus_select_cs(device_t, uint8_t); 60235537Sgberstatic int nandbus_send_command(device_t, uint8_t); 61235537Sgberstatic int nandbus_send_address(device_t, uint8_t); 62235537Sgberstatic int nandbus_start_command(device_t); 63235537Sgberstatic int nandbus_wait_ready(device_t, uint8_t *); 64235537Sgberstatic void nandbus_write_buffer(device_t, void *, uint32_t); 65235537Sgberstatic int nandbus_get_ecc(device_t, void *, uint32_t, void *, int *); 66235537Sgberstatic int nandbus_correct_ecc(device_t, void *, int, void *, void *); 67235537Sgberstatic void nandbus_lock(device_t); 68235537Sgberstatic void nandbus_unlock(device_t); 69235537Sgber 70235537Sgberstatic int nand_readid(device_t, uint8_t *, uint8_t *); 71235537Sgberstatic int nand_probe_onfi(device_t, uint8_t *); 72235537Sgberstatic int nand_reset(device_t); 73235537Sgber 74235537Sgberstruct nandbus_softc { 75235537Sgber device_t dev; 76235537Sgber struct cv nandbus_cv; 77235537Sgber struct mtx nandbus_mtx; 78235537Sgber uint8_t busy; 79235537Sgber}; 80235537Sgber 81235537Sgberstatic device_method_t nandbus_methods[] = { 82235537Sgber /* device interface */ 83235537Sgber DEVMETHOD(device_probe, nandbus_probe), 84235537Sgber DEVMETHOD(device_attach, nandbus_attach), 85235537Sgber DEVMETHOD(device_detach, nandbus_detach), 86235537Sgber DEVMETHOD(device_shutdown, bus_generic_shutdown), 87235537Sgber 88235537Sgber /* bus interface */ 89235537Sgber DEVMETHOD(bus_print_child, bus_generic_print_child), 90235537Sgber DEVMETHOD(bus_driver_added, bus_generic_driver_added), 91235537Sgber DEVMETHOD(bus_child_pnpinfo_str, nandbus_child_pnpinfo_str), 92235537Sgber DEVMETHOD(bus_child_location_str, nandbus_child_location_str), 93235537Sgber 94235537Sgber /* nandbus interface */ 95235537Sgber DEVMETHOD(nandbus_get_status, nandbus_get_status), 96235537Sgber DEVMETHOD(nandbus_read_buffer, nandbus_read_buffer), 97235537Sgber DEVMETHOD(nandbus_select_cs, nandbus_select_cs), 98235537Sgber DEVMETHOD(nandbus_send_command, nandbus_send_command), 99235537Sgber DEVMETHOD(nandbus_send_address, nandbus_send_address), 100235537Sgber DEVMETHOD(nandbus_start_command,nandbus_start_command), 101235537Sgber DEVMETHOD(nandbus_wait_ready, nandbus_wait_ready), 102235537Sgber DEVMETHOD(nandbus_write_buffer, nandbus_write_buffer), 103235537Sgber DEVMETHOD(nandbus_get_ecc, nandbus_get_ecc), 104235537Sgber DEVMETHOD(nandbus_correct_ecc, nandbus_correct_ecc), 105235537Sgber DEVMETHOD(nandbus_lock, nandbus_lock), 106235537Sgber DEVMETHOD(nandbus_unlock, nandbus_unlock), 107235537Sgber { 0, 0 } 108235537Sgber}; 109235537Sgber 110235537Sgberdevclass_t nandbus_devclass; 111235537Sgber 112235537Sgberdriver_t nandbus_driver = { 113235537Sgber "nandbus", 114235537Sgber nandbus_methods, 115235537Sgber sizeof(struct nandbus_softc) 116235537Sgber}; 117235537Sgber 118235537SgberDRIVER_MODULE(nandbus, nand, nandbus_driver, nandbus_devclass, 0, 0); 119235537Sgber 120235537Sgberint 121235537Sgbernandbus_create(device_t nfc) 122235537Sgber{ 123235537Sgber device_t child; 124235537Sgber 125235537Sgber child = device_add_child(nfc, "nandbus", -1); 126235537Sgber if (!child) 127235537Sgber return (ENODEV); 128235537Sgber 129235537Sgber bus_generic_attach(nfc); 130235537Sgber 131235537Sgber return(0); 132235537Sgber} 133235537Sgber 134235537Sgbervoid 135235537Sgbernandbus_destroy(device_t nfc) 136235537Sgber{ 137235537Sgber device_t *children; 138235537Sgber int nchildren, i; 139235537Sgber 140235537Sgber mtx_lock(&Giant); 141235537Sgber /* Detach & delete all children */ 142235537Sgber if (!device_get_children(nfc, &children, &nchildren)) { 143235537Sgber for (i = 0; i < nchildren; i++) 144235537Sgber device_delete_child(nfc, children[i]); 145235537Sgber 146235537Sgber free(children, M_TEMP); 147235537Sgber } 148235537Sgber mtx_unlock(&Giant); 149235537Sgber} 150235537Sgber 151235537Sgberstatic int 152235537Sgbernandbus_probe(device_t dev) 153235537Sgber{ 154235537Sgber 155235537Sgber device_set_desc(dev, "NAND bus"); 156235537Sgber 157235537Sgber return (0); 158235537Sgber} 159235537Sgber 160235537Sgberstatic int 161235537Sgbernandbus_attach(device_t dev) 162235537Sgber{ 163235537Sgber device_t child, nfc; 164235537Sgber struct nand_id chip_id; 165235537Sgber struct nandbus_softc *sc; 166235537Sgber struct nandbus_ivar *ivar; 167235537Sgber struct nand_softc *nfc_sc; 168235537Sgber struct nand_params *chip_params; 169235537Sgber uint8_t cs, onfi; 170235537Sgber 171235537Sgber sc = device_get_softc(dev); 172235537Sgber sc->dev = dev; 173235537Sgber 174235537Sgber nfc = device_get_parent(dev); 175235537Sgber nfc_sc = device_get_softc(nfc); 176235537Sgber 177261884Sbrueffer mtx_init(&sc->nandbus_mtx, "nandbus lock", NULL, MTX_DEF); 178235537Sgber cv_init(&sc->nandbus_cv, "nandbus cv"); 179235537Sgber 180235537Sgber /* Check each possible CS for existing nand devices */ 181235537Sgber for (cs = 0; cs < NAND_NCS; cs++) { 182235537Sgber nand_debug(NDBG_BUS,"probe chip select %x", cs); 183235537Sgber 184235537Sgber /* Select & reset chip */ 185235537Sgber if (nandbus_select_cs(dev, cs)) 186235537Sgber break; 187235537Sgber 188235537Sgber if (nand_reset(dev)) 189235537Sgber continue; 190235537Sgber 191235537Sgber /* Read manufacturer and device id */ 192235537Sgber if (nand_readid(dev, &chip_id.man_id, &chip_id.dev_id)) 193235537Sgber continue; 194235537Sgber 195235537Sgber if (chip_id.man_id == 0xff) 196235537Sgber continue; 197235537Sgber 198258740Sian /* 199258740Sian * First try to get info from the table. If that fails, see if 200258740Sian * the chip can provide ONFI info. We check the table first to 201258740Sian * allow table entries to override info from chips that are 202258740Sian * known to provide bad ONFI data. 203258740Sian */ 204258740Sian onfi = 0; 205258740Sian chip_params = nand_get_params(&chip_id); 206258740Sian if (chip_params == NULL) { 207258740Sian nand_probe_onfi(dev, &onfi); 208258740Sian } 209258740Sian 210258740Sian /* 211258740Sian * At this point it appears there is a chip at this chipselect, 212258740Sian * so if we can't work with it, whine about it. 213258740Sian */ 214258740Sian if (chip_params == NULL && onfi == 0) { 215258740Sian if (bootverbose || (nand_debug_flag & NDBG_BUS)) 216258740Sian printf("Chip params not found, chipsel: %d " 217258740Sian "(manuf: 0x%0x, chipid: 0x%0x, onfi: %d)\n", 218258740Sian cs, chip_id.man_id, chip_id.dev_id, onfi); 219235537Sgber continue; 220235537Sgber } 221235537Sgber 222235537Sgber ivar = malloc(sizeof(struct nandbus_ivar), 223235537Sgber M_NAND, M_WAITOK); 224235537Sgber 225235537Sgber if (onfi == 1) { 226235537Sgber ivar->cs = cs; 227235537Sgber ivar->cols = 0; 228235537Sgber ivar->rows = 0; 229235537Sgber ivar->params = NULL; 230235537Sgber ivar->man_id = chip_id.man_id; 231235537Sgber ivar->dev_id = chip_id.dev_id; 232235537Sgber ivar->is_onfi = onfi; 233235537Sgber ivar->chip_cdev_name = nfc_sc->chip_cdev_name; 234235537Sgber 235235537Sgber child = device_add_child(dev, NULL, -1); 236235537Sgber device_set_ivars(child, ivar); 237235537Sgber continue; 238235537Sgber } 239235537Sgber 240235537Sgber ivar->cs = cs; 241235537Sgber ivar->cols = 1; 242235537Sgber ivar->rows = 2; 243235537Sgber ivar->params = chip_params; 244235537Sgber ivar->man_id = chip_id.man_id; 245235537Sgber ivar->dev_id = chip_id.dev_id; 246235537Sgber ivar->is_onfi = onfi; 247235537Sgber ivar->chip_cdev_name = nfc_sc->chip_cdev_name; 248235537Sgber 249235537Sgber /* 250235537Sgber * Check what type of device we have. 251235537Sgber * devices bigger than 32MiB have on more row (3) 252235537Sgber */ 253235537Sgber if (chip_params->chip_size > 32) 254235537Sgber ivar->rows++; 255235537Sgber /* Large page devices have one more col (2) */ 256235537Sgber if (chip_params->chip_size >= 128 && 257235537Sgber chip_params->page_size > 512) 258235537Sgber ivar->cols++; 259235537Sgber 260235537Sgber child = device_add_child(dev, NULL, -1); 261235537Sgber device_set_ivars(child, ivar); 262235537Sgber } 263235537Sgber 264235537Sgber bus_generic_attach(dev); 265235537Sgber return (0); 266235537Sgber} 267235537Sgber 268235537Sgberstatic int 269235537Sgbernandbus_detach(device_t dev) 270235537Sgber{ 271235537Sgber struct nandbus_softc *sc; 272235537Sgber 273235537Sgber sc = device_get_softc(dev); 274235537Sgber 275235537Sgber bus_generic_detach(dev); 276235537Sgber 277235537Sgber mtx_destroy(&sc->nandbus_mtx); 278235537Sgber cv_destroy(&sc->nandbus_cv); 279235537Sgber 280235537Sgber return (0); 281235537Sgber} 282235537Sgber 283235537Sgberstatic int 284235537Sgbernandbus_child_location_str(device_t bus, device_t child, char *buf, 285235537Sgber size_t buflen) 286235537Sgber{ 287235537Sgber struct nandbus_ivar *ivar = device_get_ivars(child); 288235537Sgber 289235537Sgber snprintf(buf, buflen, "at cs#%d", ivar->cs); 290235537Sgber return (0); 291235537Sgber} 292235537Sgber 293235537Sgberstatic int 294235537Sgbernandbus_child_pnpinfo_str(device_t bus, device_t child, char *buf, 295235537Sgber size_t buflen) 296235537Sgber{ 297235537Sgber // XXX man id, model id ???? 298235537Sgber *buf = '\0'; 299235537Sgber return (0); 300235537Sgber} 301235537Sgber 302235537Sgberstatic int 303235537Sgbernand_readid(device_t bus, uint8_t *man_id, uint8_t *dev_id) 304235537Sgber{ 305235537Sgber device_t nfc; 306235537Sgber 307235537Sgber if (!bus || !man_id || !dev_id) 308235537Sgber return (EINVAL); 309235537Sgber 310235537Sgber nand_debug(NDBG_BUS,"read id"); 311235537Sgber 312235537Sgber nfc = device_get_parent(bus); 313235537Sgber 314235537Sgber if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { 315235537Sgber nand_debug(NDBG_BUS,"Error : could not send READ ID command"); 316235537Sgber return (ENXIO); 317235537Sgber } 318235537Sgber 319235537Sgber if (NFC_SEND_ADDRESS(nfc, 0)) { 320235537Sgber nand_debug(NDBG_BUS,"Error : could not sent address to chip"); 321235537Sgber return (ENXIO); 322235537Sgber } 323235537Sgber 324235537Sgber if (NFC_START_COMMAND(nfc) != 0) { 325235537Sgber nand_debug(NDBG_BUS,"Error : could not start command"); 326235537Sgber return (ENXIO); 327235537Sgber } 328235537Sgber 329235537Sgber DELAY(25); 330235537Sgber 331235537Sgber *man_id = NFC_READ_BYTE(nfc); 332235537Sgber *dev_id = NFC_READ_BYTE(nfc); 333235537Sgber 334235537Sgber nand_debug(NDBG_BUS,"manufacturer id: %x chip id: %x", *man_id, 335235537Sgber *dev_id); 336235537Sgber 337235537Sgber return (0); 338235537Sgber} 339235537Sgber 340235537Sgberstatic int 341235537Sgbernand_probe_onfi(device_t bus, uint8_t *onfi_compliant) 342235537Sgber{ 343235537Sgber device_t nfc; 344251022Sgber char onfi_id[] = {'O', 'N', 'F', 'I', '\0'}; 345235537Sgber int i; 346235537Sgber 347235537Sgber nand_debug(NDBG_BUS,"probing ONFI"); 348235537Sgber 349235537Sgber nfc = device_get_parent(bus); 350235537Sgber 351235537Sgber if (NFC_SEND_COMMAND(nfc, NAND_CMD_READ_ID)) { 352235537Sgber nand_debug(NDBG_BUS,"Error : could not sent READ ID command"); 353235537Sgber return (ENXIO); 354235537Sgber } 355235537Sgber 356235537Sgber if (NFC_SEND_ADDRESS(nfc, ONFI_SIG_ADDR)) { 357235537Sgber nand_debug(NDBG_BUS,"Error : could not sent address to chip"); 358235537Sgber return (ENXIO); 359235537Sgber } 360235537Sgber 361235537Sgber if (NFC_START_COMMAND(nfc) != 0) { 362235537Sgber nand_debug(NDBG_BUS,"Error : could not start command"); 363235537Sgber return (ENXIO); 364235537Sgber } 365235537Sgber for (i = 0; onfi_id[i] != '\0'; i++) 366235537Sgber if (NFC_READ_BYTE(nfc) != onfi_id[i]) { 367235537Sgber nand_debug(NDBG_BUS,"ONFI non-compliant"); 368235537Sgber *onfi_compliant = 0; 369235537Sgber return (0); 370235537Sgber } 371235537Sgber 372235537Sgber nand_debug(NDBG_BUS,"ONFI compliant"); 373235537Sgber *onfi_compliant = 1; 374235537Sgber 375235537Sgber return (0); 376235537Sgber} 377235537Sgber 378235537Sgberstatic int 379235537Sgbernand_reset(device_t bus) 380235537Sgber{ 381235537Sgber device_t nfc; 382235537Sgber nand_debug(NDBG_BUS,"resetting..."); 383235537Sgber 384235537Sgber nfc = device_get_parent(bus); 385235537Sgber 386235537Sgber if (NFC_SEND_COMMAND(nfc, NAND_CMD_RESET) != 0) { 387235537Sgber nand_debug(NDBG_BUS,"Error : could not sent RESET command"); 388235537Sgber return (ENXIO); 389235537Sgber } 390235537Sgber 391235537Sgber if (NFC_START_COMMAND(nfc) != 0) { 392235537Sgber nand_debug(NDBG_BUS,"Error : could not start RESET command"); 393235537Sgber return (ENXIO); 394235537Sgber } 395235537Sgber 396235537Sgber DELAY(1000); 397235537Sgber 398235537Sgber return (0); 399235537Sgber} 400235537Sgber 401235537Sgbervoid 402235537Sgbernandbus_lock(device_t dev) 403235537Sgber{ 404235537Sgber struct nandbus_softc *sc; 405235537Sgber 406235537Sgber sc = device_get_softc(dev); 407235537Sgber 408235537Sgber mtx_lock(&sc->nandbus_mtx); 409235537Sgber if (sc->busy) 410235537Sgber cv_wait(&sc->nandbus_cv, &sc->nandbus_mtx); 411235537Sgber sc->busy = 1; 412235537Sgber mtx_unlock(&sc->nandbus_mtx); 413235537Sgber} 414235537Sgber 415235537Sgbervoid 416235537Sgbernandbus_unlock(device_t dev) 417235537Sgber{ 418235537Sgber struct nandbus_softc *sc; 419235537Sgber 420235537Sgber sc = device_get_softc(dev); 421235537Sgber 422235537Sgber mtx_lock(&sc->nandbus_mtx); 423235537Sgber sc->busy = 0; 424235537Sgber cv_signal(&sc->nandbus_cv); 425235537Sgber mtx_unlock(&sc->nandbus_mtx); 426235537Sgber} 427235537Sgber 428235537Sgberint 429235537Sgbernandbus_select_cs(device_t dev, uint8_t cs) 430235537Sgber{ 431235537Sgber 432235537Sgber return (NFC_SELECT_CS(device_get_parent(dev), cs)); 433235537Sgber} 434235537Sgber 435235537Sgberint 436235537Sgbernandbus_send_command(device_t dev, uint8_t command) 437235537Sgber{ 438235537Sgber int err; 439235537Sgber 440235537Sgber if ((err = NFC_SEND_COMMAND(device_get_parent(dev), command))) 441235537Sgber nand_debug(NDBG_BUS,"Err: Could not send command %x, err %x", 442235537Sgber command, err); 443235537Sgber 444235537Sgber return (err); 445235537Sgber} 446235537Sgber 447235537Sgberint 448235537Sgbernandbus_send_address(device_t dev, uint8_t address) 449235537Sgber{ 450235537Sgber int err; 451235537Sgber 452235537Sgber if ((err = NFC_SEND_ADDRESS(device_get_parent(dev), address))) 453235537Sgber nand_debug(NDBG_BUS,"Err: Could not send address %x, err %x", 454235537Sgber address, err); 455235537Sgber 456235537Sgber return (err); 457235537Sgber} 458235537Sgber 459235537Sgberint 460235537Sgbernandbus_start_command(device_t dev) 461235537Sgber{ 462235537Sgber int err; 463235537Sgber 464235537Sgber if ((err = NFC_START_COMMAND(device_get_parent(dev)))) 465235537Sgber nand_debug(NDBG_BUS,"Err: Could not start command, err %x", 466235537Sgber err); 467235537Sgber 468235537Sgber return (err); 469235537Sgber} 470235537Sgber 471235537Sgbervoid 472235537Sgbernandbus_read_buffer(device_t dev, void *buf, uint32_t len) 473235537Sgber{ 474235537Sgber 475235537Sgber NFC_READ_BUF(device_get_parent(dev), buf, len); 476235537Sgber} 477235537Sgber 478235537Sgbervoid 479235537Sgbernandbus_write_buffer(device_t dev, void *buf, uint32_t len) 480235537Sgber{ 481235537Sgber 482235537Sgber NFC_WRITE_BUF(device_get_parent(dev), buf, len); 483235537Sgber} 484235537Sgber 485235537Sgberint 486235537Sgbernandbus_get_status(device_t dev, uint8_t *status) 487235537Sgber{ 488235537Sgber int err; 489235537Sgber 490235537Sgber if ((err = NANDBUS_SEND_COMMAND(dev, NAND_CMD_STATUS))) 491235537Sgber return (err); 492235537Sgber if ((err = NANDBUS_START_COMMAND(dev))) 493235537Sgber return (err); 494235537Sgber 495235537Sgber *status = NFC_READ_BYTE(device_get_parent(dev)); 496235537Sgber 497235537Sgber return (0); 498235537Sgber} 499235537Sgber 500235537Sgberint 501235537Sgbernandbus_wait_ready(device_t dev, uint8_t *status) 502235537Sgber{ 503235537Sgber struct timeval tv, tv2; 504235537Sgber 505235537Sgber tv2.tv_sec = 0; 506260180Simp tv2.tv_usec = 50 * 5000; /* 250ms */ 507235537Sgber 508235537Sgber getmicrotime(&tv); 509235537Sgber timevaladd(&tv, &tv2); 510235537Sgber 511235537Sgber do { 512235537Sgber if (NANDBUS_GET_STATUS(dev, status)) 513235537Sgber return (ENXIO); 514235537Sgber 515235537Sgber if (*status & NAND_STATUS_RDY) 516235537Sgber return (0); 517235537Sgber 518235537Sgber getmicrotime(&tv2); 519235537Sgber } while (timevalcmp(&tv2, &tv, <=)); 520235537Sgber 521235537Sgber return (EBUSY); 522235537Sgber} 523235537Sgber 524235537Sgberint 525235537Sgbernandbus_get_ecc(device_t dev, void *buf, uint32_t pagesize, void *ecc, 526235537Sgber int *needwrite) 527235537Sgber{ 528235537Sgber 529235537Sgber return (NFC_GET_ECC(device_get_parent(dev), buf, pagesize, ecc, needwrite)); 530235537Sgber} 531235537Sgber 532235537Sgberint 533235537Sgbernandbus_correct_ecc(device_t dev, void *buf, int pagesize, void *readecc, 534235537Sgber void *calcecc) 535235537Sgber{ 536235537Sgber 537235537Sgber return (NFC_CORRECT_ECC(device_get_parent(dev), buf, pagesize, 538235537Sgber readecc, calcecc)); 539235537Sgber} 540235537Sgber 541