| 1 | /* |
| 2 | * Copyright (C) 2009-2012 Gabor Juhos <juhosg@openwrt.org> |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify it |
| 5 | * under the terms of the GNU General Public License version 2 as published |
| 6 | * by the Free Software Foundation. |
| 7 | */ |
| 8 | |
| 9 | #include <linux/init.h> |
| 10 | #include <linux/spi/spi.h> |
| 11 | #include <linux/spi/flash.h> |
| 12 | #include <linux/mtd/mtd.h> |
| 13 | #include <linux/mtd/partitions.h> |
| 14 | #include <linux/mtd/concat.h> |
| 15 | |
| 16 | #include "dev-spi.h" |
| 17 | #include "dev-m25p80.h" |
| 18 | |
| 19 | static struct ath79_spi_controller_data ath79_spi0_cdata = |
| 20 | { |
| 21 | .cs_type = ATH79_SPI_CS_TYPE_INTERNAL, |
| 22 | .cs_line = 0, |
| 23 | }; |
| 24 | |
| 25 | static struct ath79_spi_controller_data ath79_spi1_cdata = |
| 26 | { |
| 27 | .cs_type = ATH79_SPI_CS_TYPE_INTERNAL, |
| 28 | .cs_line = 1, |
| 29 | }; |
| 30 | |
| 31 | static struct spi_board_info ath79_spi_info[] = { |
| 32 | { |
| 33 | .bus_num = 0, |
| 34 | .chip_select = 0, |
| 35 | .max_speed_hz = 25000000, |
| 36 | .modalias = "m25p80", |
| 37 | .controller_data = &ath79_spi0_cdata, |
| 38 | }, |
| 39 | { |
| 40 | .bus_num = 0, |
| 41 | .chip_select = 1, |
| 42 | .max_speed_hz = 25000000, |
| 43 | .modalias = "m25p80", |
| 44 | .controller_data = &ath79_spi1_cdata, |
| 45 | } |
| 46 | }; |
| 47 | |
| 48 | static struct ath79_spi_platform_data ath79_spi_data; |
| 49 | |
| 50 | void __init ath79_register_m25p80(struct flash_platform_data *pdata) |
| 51 | { |
| 52 | ath79_spi_data.bus_num = 0; |
| 53 | ath79_spi_data.num_chipselect = 1; |
| 54 | ath79_spi0_cdata.is_flash = true; |
| 55 | ath79_spi_info[0].platform_data = pdata; |
| 56 | ath79_register_spi(&ath79_spi_data, ath79_spi_info, 1); |
| 57 | } |
| 58 | |
| 59 | static struct flash_platform_data *multi_pdata; |
| 60 | |
| 61 | static struct mtd_info *concat_devs[2] = { NULL, NULL }; |
| 62 | static struct work_struct mtd_concat_work; |
| 63 | |
| 64 | static void mtd_concat_add_work(struct work_struct *work) |
| 65 | { |
| 66 | struct mtd_info *mtd; |
| 67 | |
| 68 | mtd = mtd_concat_create(concat_devs, ARRAY_SIZE(concat_devs), "flash"); |
| 69 | |
| 70 | mtd_device_register(mtd, multi_pdata->parts, multi_pdata->nr_parts); |
| 71 | } |
| 72 | |
| 73 | static void mtd_concat_add(struct mtd_info *mtd) |
| 74 | { |
| 75 | static bool registered = false; |
| 76 | |
| 77 | if (registered) |
| 78 | return; |
| 79 | |
| 80 | if (!strcmp(mtd->name, "spi0.0")) |
| 81 | concat_devs[0] = mtd; |
| 82 | else if (!strcmp(mtd->name, "spi0.1")) |
| 83 | concat_devs[1] = mtd; |
| 84 | else |
| 85 | return; |
| 86 | |
| 87 | if (!concat_devs[0] || !concat_devs[1]) |
| 88 | return; |
| 89 | |
| 90 | registered = true; |
| 91 | INIT_WORK(&mtd_concat_work, mtd_concat_add_work); |
| 92 | schedule_work(&mtd_concat_work); |
| 93 | } |
| 94 | |
| 95 | static void mtd_concat_remove(struct mtd_info *mtd) |
| 96 | { |
| 97 | } |
| 98 | |
| 99 | static void add_mtd_concat_notifier(void) |
| 100 | { |
| 101 | static struct mtd_notifier not = { |
| 102 | .add = mtd_concat_add, |
| 103 | .remove = mtd_concat_remove, |
| 104 | }; |
| 105 | |
| 106 | register_mtd_user(¬); |
| 107 | } |
| 108 | |
| 109 | |
| 110 | void __init ath79_register_m25p80_multi(struct flash_platform_data *pdata) |
| 111 | { |
| 112 | multi_pdata = pdata; |
| 113 | add_mtd_concat_notifier(); |
| 114 | ath79_spi_data.bus_num = 0; |
| 115 | ath79_spi_data.num_chipselect = 2; |
| 116 | ath79_register_spi(&ath79_spi_data, ath79_spi_info, 2); |
| 117 | } |
| 118 | |