1*dcc7d344SVignesh Raghavendra // SPDX-License-Identifier: GPL-2.0 2*dcc7d344SVignesh Raghavendra // 3*dcc7d344SVignesh Raghavendra // Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ 4*dcc7d344SVignesh Raghavendra // Author: Vignesh Raghavendra <vigneshr@ti.com> 5*dcc7d344SVignesh Raghavendra 6*dcc7d344SVignesh Raghavendra #include <linux/err.h> 7*dcc7d344SVignesh Raghavendra #include <linux/kernel.h> 8*dcc7d344SVignesh Raghavendra #include <linux/module.h> 9*dcc7d344SVignesh Raghavendra #include <linux/mtd/hyperbus.h> 10*dcc7d344SVignesh Raghavendra #include <linux/mtd/map.h> 11*dcc7d344SVignesh Raghavendra #include <linux/mtd/mtd.h> 12*dcc7d344SVignesh Raghavendra #include <linux/of.h> 13*dcc7d344SVignesh Raghavendra #include <linux/of_address.h> 14*dcc7d344SVignesh Raghavendra #include <linux/types.h> 15*dcc7d344SVignesh Raghavendra 16*dcc7d344SVignesh Raghavendra static struct hyperbus_device *map_to_hbdev(struct map_info *map) 17*dcc7d344SVignesh Raghavendra { 18*dcc7d344SVignesh Raghavendra return container_of(map, struct hyperbus_device, map); 19*dcc7d344SVignesh Raghavendra } 20*dcc7d344SVignesh Raghavendra 21*dcc7d344SVignesh Raghavendra static map_word hyperbus_read16(struct map_info *map, unsigned long addr) 22*dcc7d344SVignesh Raghavendra { 23*dcc7d344SVignesh Raghavendra struct hyperbus_device *hbdev = map_to_hbdev(map); 24*dcc7d344SVignesh Raghavendra struct hyperbus_ctlr *ctlr = hbdev->ctlr; 25*dcc7d344SVignesh Raghavendra map_word read_data; 26*dcc7d344SVignesh Raghavendra 27*dcc7d344SVignesh Raghavendra read_data.x[0] = ctlr->ops->read16(hbdev, addr); 28*dcc7d344SVignesh Raghavendra 29*dcc7d344SVignesh Raghavendra return read_data; 30*dcc7d344SVignesh Raghavendra } 31*dcc7d344SVignesh Raghavendra 32*dcc7d344SVignesh Raghavendra static void hyperbus_write16(struct map_info *map, map_word d, 33*dcc7d344SVignesh Raghavendra unsigned long addr) 34*dcc7d344SVignesh Raghavendra { 35*dcc7d344SVignesh Raghavendra struct hyperbus_device *hbdev = map_to_hbdev(map); 36*dcc7d344SVignesh Raghavendra struct hyperbus_ctlr *ctlr = hbdev->ctlr; 37*dcc7d344SVignesh Raghavendra 38*dcc7d344SVignesh Raghavendra ctlr->ops->write16(hbdev, addr, d.x[0]); 39*dcc7d344SVignesh Raghavendra } 40*dcc7d344SVignesh Raghavendra 41*dcc7d344SVignesh Raghavendra static void hyperbus_copy_from(struct map_info *map, void *to, 42*dcc7d344SVignesh Raghavendra unsigned long from, ssize_t len) 43*dcc7d344SVignesh Raghavendra { 44*dcc7d344SVignesh Raghavendra struct hyperbus_device *hbdev = map_to_hbdev(map); 45*dcc7d344SVignesh Raghavendra struct hyperbus_ctlr *ctlr = hbdev->ctlr; 46*dcc7d344SVignesh Raghavendra 47*dcc7d344SVignesh Raghavendra ctlr->ops->copy_from(hbdev, to, from, len); 48*dcc7d344SVignesh Raghavendra } 49*dcc7d344SVignesh Raghavendra 50*dcc7d344SVignesh Raghavendra static void hyperbus_copy_to(struct map_info *map, unsigned long to, 51*dcc7d344SVignesh Raghavendra const void *from, ssize_t len) 52*dcc7d344SVignesh Raghavendra { 53*dcc7d344SVignesh Raghavendra struct hyperbus_device *hbdev = map_to_hbdev(map); 54*dcc7d344SVignesh Raghavendra struct hyperbus_ctlr *ctlr = hbdev->ctlr; 55*dcc7d344SVignesh Raghavendra 56*dcc7d344SVignesh Raghavendra ctlr->ops->copy_to(hbdev, to, from, len); 57*dcc7d344SVignesh Raghavendra } 58*dcc7d344SVignesh Raghavendra 59*dcc7d344SVignesh Raghavendra int hyperbus_register_device(struct hyperbus_device *hbdev) 60*dcc7d344SVignesh Raghavendra { 61*dcc7d344SVignesh Raghavendra const struct hyperbus_ops *ops; 62*dcc7d344SVignesh Raghavendra struct hyperbus_ctlr *ctlr; 63*dcc7d344SVignesh Raghavendra struct device_node *np; 64*dcc7d344SVignesh Raghavendra struct map_info *map; 65*dcc7d344SVignesh Raghavendra struct resource res; 66*dcc7d344SVignesh Raghavendra struct device *dev; 67*dcc7d344SVignesh Raghavendra int ret; 68*dcc7d344SVignesh Raghavendra 69*dcc7d344SVignesh Raghavendra if (!hbdev || !hbdev->np || !hbdev->ctlr || !hbdev->ctlr->dev) { 70*dcc7d344SVignesh Raghavendra pr_err("hyperbus: please fill all the necessary fields!\n"); 71*dcc7d344SVignesh Raghavendra return -EINVAL; 72*dcc7d344SVignesh Raghavendra } 73*dcc7d344SVignesh Raghavendra 74*dcc7d344SVignesh Raghavendra np = hbdev->np; 75*dcc7d344SVignesh Raghavendra ctlr = hbdev->ctlr; 76*dcc7d344SVignesh Raghavendra if (!of_device_is_compatible(np, "cypress,hyperflash")) 77*dcc7d344SVignesh Raghavendra return -ENODEV; 78*dcc7d344SVignesh Raghavendra 79*dcc7d344SVignesh Raghavendra hbdev->memtype = HYPERFLASH; 80*dcc7d344SVignesh Raghavendra 81*dcc7d344SVignesh Raghavendra ret = of_address_to_resource(np, 0, &res); 82*dcc7d344SVignesh Raghavendra if (ret) 83*dcc7d344SVignesh Raghavendra return ret; 84*dcc7d344SVignesh Raghavendra 85*dcc7d344SVignesh Raghavendra dev = ctlr->dev; 86*dcc7d344SVignesh Raghavendra map = &hbdev->map; 87*dcc7d344SVignesh Raghavendra map->size = resource_size(&res); 88*dcc7d344SVignesh Raghavendra map->virt = devm_ioremap_resource(dev, &res); 89*dcc7d344SVignesh Raghavendra if (IS_ERR(map->virt)) 90*dcc7d344SVignesh Raghavendra return PTR_ERR(map->virt); 91*dcc7d344SVignesh Raghavendra 92*dcc7d344SVignesh Raghavendra map->name = dev_name(dev); 93*dcc7d344SVignesh Raghavendra map->bankwidth = 2; 94*dcc7d344SVignesh Raghavendra map->device_node = np; 95*dcc7d344SVignesh Raghavendra 96*dcc7d344SVignesh Raghavendra simple_map_init(map); 97*dcc7d344SVignesh Raghavendra ops = ctlr->ops; 98*dcc7d344SVignesh Raghavendra if (ops) { 99*dcc7d344SVignesh Raghavendra if (ops->read16) 100*dcc7d344SVignesh Raghavendra map->read = hyperbus_read16; 101*dcc7d344SVignesh Raghavendra if (ops->write16) 102*dcc7d344SVignesh Raghavendra map->write = hyperbus_write16; 103*dcc7d344SVignesh Raghavendra if (ops->copy_to) 104*dcc7d344SVignesh Raghavendra map->copy_to = hyperbus_copy_to; 105*dcc7d344SVignesh Raghavendra if (ops->copy_from) 106*dcc7d344SVignesh Raghavendra map->copy_from = hyperbus_copy_from; 107*dcc7d344SVignesh Raghavendra 108*dcc7d344SVignesh Raghavendra if (ops->calibrate && !ctlr->calibrated) { 109*dcc7d344SVignesh Raghavendra ret = ops->calibrate(hbdev); 110*dcc7d344SVignesh Raghavendra if (!ret) { 111*dcc7d344SVignesh Raghavendra dev_err(dev, "Calibration failed\n"); 112*dcc7d344SVignesh Raghavendra return -ENODEV; 113*dcc7d344SVignesh Raghavendra } 114*dcc7d344SVignesh Raghavendra ctlr->calibrated = true; 115*dcc7d344SVignesh Raghavendra } 116*dcc7d344SVignesh Raghavendra } 117*dcc7d344SVignesh Raghavendra 118*dcc7d344SVignesh Raghavendra hbdev->mtd = do_map_probe("cfi_probe", map); 119*dcc7d344SVignesh Raghavendra if (!hbdev->mtd) { 120*dcc7d344SVignesh Raghavendra dev_err(dev, "probing of hyperbus device failed\n"); 121*dcc7d344SVignesh Raghavendra return -ENODEV; 122*dcc7d344SVignesh Raghavendra } 123*dcc7d344SVignesh Raghavendra 124*dcc7d344SVignesh Raghavendra hbdev->mtd->dev.parent = dev; 125*dcc7d344SVignesh Raghavendra mtd_set_of_node(hbdev->mtd, np); 126*dcc7d344SVignesh Raghavendra 127*dcc7d344SVignesh Raghavendra ret = mtd_device_register(hbdev->mtd, NULL, 0); 128*dcc7d344SVignesh Raghavendra if (ret) { 129*dcc7d344SVignesh Raghavendra dev_err(dev, "failed to register mtd device\n"); 130*dcc7d344SVignesh Raghavendra map_destroy(hbdev->mtd); 131*dcc7d344SVignesh Raghavendra return ret; 132*dcc7d344SVignesh Raghavendra } 133*dcc7d344SVignesh Raghavendra 134*dcc7d344SVignesh Raghavendra return 0; 135*dcc7d344SVignesh Raghavendra } 136*dcc7d344SVignesh Raghavendra EXPORT_SYMBOL_GPL(hyperbus_register_device); 137*dcc7d344SVignesh Raghavendra 138*dcc7d344SVignesh Raghavendra int hyperbus_unregister_device(struct hyperbus_device *hbdev) 139*dcc7d344SVignesh Raghavendra { 140*dcc7d344SVignesh Raghavendra int ret = 0; 141*dcc7d344SVignesh Raghavendra 142*dcc7d344SVignesh Raghavendra if (hbdev && hbdev->mtd) { 143*dcc7d344SVignesh Raghavendra ret = mtd_device_unregister(hbdev->mtd); 144*dcc7d344SVignesh Raghavendra map_destroy(hbdev->mtd); 145*dcc7d344SVignesh Raghavendra } 146*dcc7d344SVignesh Raghavendra 147*dcc7d344SVignesh Raghavendra return ret; 148*dcc7d344SVignesh Raghavendra } 149*dcc7d344SVignesh Raghavendra EXPORT_SYMBOL_GPL(hyperbus_unregister_device); 150*dcc7d344SVignesh Raghavendra 151*dcc7d344SVignesh Raghavendra MODULE_DESCRIPTION("HyperBus Framework"); 152*dcc7d344SVignesh Raghavendra MODULE_LICENSE("GPL v2"); 153*dcc7d344SVignesh Raghavendra MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>"); 154