-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
David Griego
authored and
David Woodhouse
committed
Mar 11, 2011
1 parent
04f6a68
commit 36cacbd
Showing
5 changed files
with
312 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: a321590246202f2598aca2f4ef63b992e8fc97ef | ||
refs/heads/master: dcfb81d61da1367e52f7f7e3ceff0d0044c3c7ee |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,272 @@ | ||
/* | ||
* Interface for NOR flash driver whose high address lines are latched | ||
* | ||
* Copyright © 2000 Nicolas Pitre <nico@cam.org> | ||
* Copyright © 2005-2008 Analog Devices Inc. | ||
* Copyright © 2008 MontaVista Software, Inc. <source@mvista.com> | ||
* | ||
* This file is licensed under the terms of the GNU General Public License | ||
* version 2. This program is licensed "as is" without any warranty of any | ||
* kind, whether express or implied. | ||
*/ | ||
|
||
#include <linux/init.h> | ||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/mtd/mtd.h> | ||
#include <linux/mtd/map.h> | ||
#include <linux/mtd/partitions.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/mtd/latch-addr-flash.h> | ||
#include <linux/slab.h> | ||
|
||
#define DRIVER_NAME "latch-addr-flash" | ||
|
||
struct latch_addr_flash_info { | ||
struct mtd_info *mtd; | ||
struct map_info map; | ||
struct resource *res; | ||
|
||
void (*set_window)(unsigned long offset, void *data); | ||
void *data; | ||
|
||
/* cache; could be found out of res */ | ||
unsigned long win_mask; | ||
|
||
int nr_parts; | ||
struct mtd_partition *parts; | ||
|
||
spinlock_t lock; | ||
}; | ||
|
||
static map_word lf_read(struct map_info *map, unsigned long ofs) | ||
{ | ||
struct latch_addr_flash_info *info; | ||
map_word datum; | ||
|
||
info = (struct latch_addr_flash_info *)map->map_priv_1; | ||
|
||
spin_lock(&info->lock); | ||
|
||
info->set_window(ofs, info->data); | ||
datum = inline_map_read(map, info->win_mask & ofs); | ||
|
||
spin_unlock(&info->lock); | ||
|
||
return datum; | ||
} | ||
|
||
static void lf_write(struct map_info *map, map_word datum, unsigned long ofs) | ||
{ | ||
struct latch_addr_flash_info *info; | ||
|
||
info = (struct latch_addr_flash_info *)map->map_priv_1; | ||
|
||
spin_lock(&info->lock); | ||
|
||
info->set_window(ofs, info->data); | ||
inline_map_write(map, datum, info->win_mask & ofs); | ||
|
||
spin_unlock(&info->lock); | ||
} | ||
|
||
static void lf_copy_from(struct map_info *map, void *to, | ||
unsigned long from, ssize_t len) | ||
{ | ||
struct latch_addr_flash_info *info = | ||
(struct latch_addr_flash_info *) map->map_priv_1; | ||
unsigned n; | ||
|
||
while (len > 0) { | ||
n = info->win_mask + 1 - (from & info->win_mask); | ||
if (n > len) | ||
n = len; | ||
|
||
spin_lock(&info->lock); | ||
|
||
info->set_window(from, info->data); | ||
memcpy_fromio(to, map->virt + (from & info->win_mask), n); | ||
|
||
spin_unlock(&info->lock); | ||
|
||
to += n; | ||
from += n; | ||
len -= n; | ||
} | ||
} | ||
|
||
static char *rom_probe_types[] = { "cfi_probe", NULL }; | ||
|
||
static char *part_probe_types[] = { "cmdlinepart", NULL }; | ||
|
||
static int latch_addr_flash_remove(struct platform_device *dev) | ||
{ | ||
struct latch_addr_flash_info *info; | ||
struct latch_addr_flash_data *latch_addr_data; | ||
|
||
info = platform_get_drvdata(dev); | ||
if (info == NULL) | ||
return 0; | ||
platform_set_drvdata(dev, NULL); | ||
|
||
latch_addr_data = dev->dev.platform_data; | ||
|
||
if (info->mtd != NULL) { | ||
if (mtd_has_partitions()) { | ||
if (info->nr_parts) { | ||
del_mtd_partitions(info->mtd); | ||
kfree(info->parts); | ||
} else if (latch_addr_data->nr_parts) { | ||
del_mtd_partitions(info->mtd); | ||
} else { | ||
del_mtd_device(info->mtd); | ||
} | ||
} else { | ||
del_mtd_device(info->mtd); | ||
} | ||
map_destroy(info->mtd); | ||
} | ||
|
||
if (info->map.virt != NULL) | ||
iounmap(info->map.virt); | ||
|
||
if (info->res != NULL) | ||
release_mem_region(info->res->start, resource_size(info->res)); | ||
|
||
kfree(info); | ||
|
||
if (latch_addr_data->done) | ||
latch_addr_data->done(latch_addr_data->data); | ||
|
||
return 0; | ||
} | ||
|
||
static int __devinit latch_addr_flash_probe(struct platform_device *dev) | ||
{ | ||
struct latch_addr_flash_data *latch_addr_data; | ||
struct latch_addr_flash_info *info; | ||
resource_size_t win_base = dev->resource->start; | ||
resource_size_t win_size = resource_size(dev->resource); | ||
char **probe_type; | ||
int chipsel; | ||
int err; | ||
|
||
latch_addr_data = dev->dev.platform_data; | ||
if (latch_addr_data == NULL) | ||
return -ENODEV; | ||
|
||
pr_notice("latch-addr platform flash device: %#llx byte " | ||
"window at %#.8llx\n", | ||
(unsigned long long)win_size, (unsigned long long)win_base); | ||
|
||
chipsel = dev->id; | ||
|
||
if (latch_addr_data->init) { | ||
err = latch_addr_data->init(latch_addr_data->data, chipsel); | ||
if (err != 0) | ||
return err; | ||
} | ||
|
||
info = kzalloc(sizeof(struct latch_addr_flash_info), GFP_KERNEL); | ||
if (info == NULL) { | ||
err = -ENOMEM; | ||
goto done; | ||
} | ||
|
||
platform_set_drvdata(dev, info); | ||
|
||
info->res = request_mem_region(win_base, win_size, DRIVER_NAME); | ||
if (info->res == NULL) { | ||
dev_err(&dev->dev, "Could not reserve memory region\n"); | ||
err = -EBUSY; | ||
goto free_info; | ||
} | ||
|
||
info->map.name = DRIVER_NAME; | ||
info->map.size = latch_addr_data->size; | ||
info->map.bankwidth = latch_addr_data->width; | ||
|
||
info->map.phys = NO_XIP; | ||
info->map.virt = ioremap(win_base, win_size); | ||
if (!info->map.virt) { | ||
err = -ENOMEM; | ||
goto free_res; | ||
} | ||
|
||
info->map.map_priv_1 = (unsigned long)info; | ||
|
||
info->map.read = lf_read; | ||
info->map.copy_from = lf_copy_from; | ||
info->map.write = lf_write; | ||
info->set_window = latch_addr_data->set_window; | ||
info->data = latch_addr_data->data; | ||
info->win_mask = win_size - 1; | ||
|
||
spin_lock_init(&info->lock); | ||
|
||
for (probe_type = rom_probe_types; !info->mtd && *probe_type; | ||
probe_type++) | ||
info->mtd = do_map_probe(*probe_type, &info->map); | ||
|
||
if (info->mtd == NULL) { | ||
dev_err(&dev->dev, "map_probe failed\n"); | ||
err = -ENODEV; | ||
goto iounmap; | ||
} | ||
info->mtd->owner = THIS_MODULE; | ||
|
||
if (mtd_has_partitions()) { | ||
|
||
err = parse_mtd_partitions(info->mtd, | ||
(const char **)part_probe_types, | ||
&info->parts, 0); | ||
if (err > 0) { | ||
add_mtd_partitions(info->mtd, info->parts, err); | ||
return 0; | ||
} | ||
if (latch_addr_data->nr_parts) { | ||
pr_notice("Using latch-addr-flash partition information\n"); | ||
add_mtd_partitions(info->mtd, latch_addr_data->parts, | ||
latch_addr_data->nr_parts); | ||
return 0; | ||
} | ||
} | ||
add_mtd_device(info->mtd); | ||
return 0; | ||
|
||
iounmap: | ||
iounmap(info->map.virt); | ||
free_res: | ||
release_mem_region(info->res->start, resource_size(info->res)); | ||
free_info: | ||
kfree(info); | ||
done: | ||
if (latch_addr_data->done) | ||
latch_addr_data->done(latch_addr_data->data); | ||
return err; | ||
} | ||
|
||
static struct platform_driver latch_addr_flash_driver = { | ||
.probe = latch_addr_flash_probe, | ||
.remove = __devexit_p(latch_addr_flash_remove), | ||
.driver = { | ||
.name = DRIVER_NAME, | ||
}, | ||
}; | ||
|
||
static int __init latch_addr_flash_init(void) | ||
{ | ||
return platform_driver_register(&latch_addr_flash_driver); | ||
} | ||
module_init(latch_addr_flash_init); | ||
|
||
static void __exit latch_addr_flash_exit(void) | ||
{ | ||
platform_driver_unregister(&latch_addr_flash_driver); | ||
} | ||
module_exit(latch_addr_flash_exit); | ||
|
||
MODULE_AUTHOR("David Griego <dgriego@mvista.com>"); | ||
MODULE_DESCRIPTION("MTD map driver for flashes addressed physically with upper " | ||
"address lines being set board specifically"); | ||
MODULE_LICENSE("GPL v2"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Interface for NOR flash driver whose high address lines are latched | ||
* | ||
* Copyright © 2008 MontaVista Software, Inc. <source@mvista.com> | ||
* | ||
* This file is licensed under the terms of the GNU General Public License | ||
* version 2. This program is licensed "as is" without any warranty of any | ||
* kind, whether express or implied. | ||
*/ | ||
#ifndef __LATCH_ADDR_FLASH__ | ||
#define __LATCH_ADDR_FLASH__ | ||
|
||
struct map_info; | ||
struct mtd_partition; | ||
|
||
struct latch_addr_flash_data { | ||
unsigned int width; | ||
unsigned int size; | ||
|
||
int (*init)(void *data, int cs); | ||
void (*done)(void *data); | ||
void (*set_window)(unsigned long offset, void *data); | ||
void *data; | ||
|
||
unsigned int nr_parts; | ||
struct mtd_partition *parts; | ||
}; | ||
|
||
#endif |