mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
spi nor: spicc: change to use spicc to access spi nor [1/1]
PD#TV-8401 Problem: Customer needs to access spi nor by the spicc. Solution: add spi nor interfaces in spicc driver. add gd25q80c/FM25Q08A surpport Verify: tl1 x301 Change-Id: If94858d46c31fea6b37034a8b1dfe94a9e9f4603 Signed-off-by: Sunny Luo <sunny.luo@amlogic.com>
This commit is contained in:
@@ -42,6 +42,8 @@
|
||||
i2c2 = &i2c2;
|
||||
i2c3 = &i2c3;
|
||||
i2c4 = &i2c_AO;
|
||||
spi0 = &spicc_a;
|
||||
spi1 = &spicc1;
|
||||
};
|
||||
|
||||
memory@00000000 {
|
||||
@@ -1856,6 +1858,72 @@
|
||||
status = "disable";
|
||||
};
|
||||
|
||||
ðmac {
|
||||
status = "okay";
|
||||
pinctrl-names = "internal_eth_pins";
|
||||
pinctrl-0 = <&internal_eth_pins>;
|
||||
mc_val = <0x4be04>;
|
||||
|
||||
internal_phy=<1>;
|
||||
};
|
||||
|
||||
&uart_A {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&dwc3 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2_phy_v2 {
|
||||
status = "okay";
|
||||
portnum = <3>;
|
||||
};
|
||||
|
||||
&usb3_phy_v2 {
|
||||
status = "okay";
|
||||
portnum = <0>;
|
||||
otg = <0>;
|
||||
};
|
||||
|
||||
&dwc2_a {
|
||||
status = "okay";
|
||||
/** 0: normal, 1: otg+dwc3 host only, 2: otg+dwc3 device only*/
|
||||
controller-type = <1>;
|
||||
};
|
||||
|
||||
&spicc0 {
|
||||
status = "disabled";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spicc0_pins_h>;
|
||||
cs-gpios = <&gpio GPIOH_20 0>;
|
||||
};
|
||||
|
||||
&spicc_a {
|
||||
status = "okay";
|
||||
pinctrl-names= "default";
|
||||
pinctrl-0=<&spicc0_pins_h>;
|
||||
cs-gpios = <&gpio GPIOH_20 GPIO_ACTIVE_HIGH>;
|
||||
spi-nor@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
status = "okay";
|
||||
frequency = <40000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&meson_fb {
|
||||
status = "okay";
|
||||
display_size_default = <1920 1080 1920 2160 32>;
|
||||
mem_size = <0x00800000 0x1980000 0x100000 0x800000>;
|
||||
logo_addr = "0x7f800000";
|
||||
mem_alloc = <0>;
|
||||
pxp_mode = <0>; /** 0:normal mode 1:pxp mode */
|
||||
};
|
||||
|
||||
&pwm_AO_cd {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie_A {
|
||||
reset-gpio = <&gpio GPIOX_7 GPIO_ACTIVE_HIGH>;
|
||||
status = "disable";
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
i2c2 = &i2c2;
|
||||
i2c3 = &i2c3;
|
||||
i2c4 = &i2c_AO;
|
||||
spi0 = &spicc0;
|
||||
spi0 = &spicc_a;
|
||||
spi1 = &spicc1;
|
||||
};
|
||||
|
||||
@@ -2046,12 +2046,24 @@
|
||||
};
|
||||
|
||||
&spicc0 {
|
||||
status = "okay";
|
||||
status = "disabled";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spicc0_pins_h>;
|
||||
cs-gpios = <&gpio GPIOH_20 0>;
|
||||
};
|
||||
|
||||
&spicc_a {
|
||||
status = "okay";
|
||||
pinctrl-names= "default";
|
||||
pinctrl-0=<&spicc0_pins_h>;
|
||||
cs-gpios = <&gpio GPIOH_20 GPIO_ACTIVE_HIGH>;
|
||||
spi-nor@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
status = "okay";
|
||||
frequency = <40000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&meson_fb {
|
||||
status = "okay";
|
||||
display_size_default = <1920 1080 1920 2160 32>;
|
||||
|
||||
@@ -389,6 +389,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
|
||||
CONFIG_MTD_BLOCK=y
|
||||
CONFIG_MTD_OOPS=y
|
||||
CONFIG_MTD_NAND=y
|
||||
CONFIG_MTD_SPI_NOR=y
|
||||
CONFIG_MTD_UBI=y
|
||||
CONFIG_ZRAM=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
i2c2 = &i2c2;
|
||||
i2c3 = &i2c3;
|
||||
i2c4 = &i2c_AO;
|
||||
spi0 = &spicc_a;
|
||||
};
|
||||
|
||||
memory@00000000 {
|
||||
@@ -1818,12 +1819,24 @@
|
||||
};
|
||||
|
||||
&spicc0 {
|
||||
status = "okay";
|
||||
status = "disabled";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spicc0_pins_h>;
|
||||
cs-gpios = <&gpio GPIOH_20 0>;
|
||||
};
|
||||
|
||||
&spicc_a {
|
||||
status = "okay";
|
||||
pinctrl-names= "default";
|
||||
pinctrl-0=<&spicc0_pins_h>;
|
||||
cs-gpios = <&gpio GPIOH_20 GPIO_ACTIVE_HIGH>;
|
||||
spi-nor@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
status = "okay";
|
||||
frequency = <40000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&meson_fb {
|
||||
status = "okay";
|
||||
display_size_default = <1920 1080 1920 2160 32>;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
i2c2 = &i2c2;
|
||||
i2c3 = &i2c3;
|
||||
i2c4 = &i2c_AO;
|
||||
spi0 = &spicc_a;
|
||||
};
|
||||
|
||||
memory@00000000 {
|
||||
@@ -1813,12 +1814,24 @@
|
||||
};
|
||||
|
||||
&spicc0 {
|
||||
status = "okay";
|
||||
status = "disabled";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spicc0_pins_h>;
|
||||
cs-gpios = <&gpio GPIOH_20 0>;
|
||||
};
|
||||
|
||||
&spicc_a {
|
||||
status = "okay";
|
||||
pinctrl-names= "default";
|
||||
pinctrl-0=<&spicc0_pins_h>;
|
||||
cs-gpios = <&gpio GPIOH_20 GPIO_ACTIVE_HIGH>;
|
||||
spi-nor@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
status = "okay";
|
||||
frequency = <40000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&meson_fb {
|
||||
status = "okay";
|
||||
display_size_default = <1920 1080 1920 2160 32>;
|
||||
|
||||
@@ -384,6 +384,7 @@ CONFIG_MTD_CMDLINE_PARTS=y
|
||||
CONFIG_MTD_BLOCK=y
|
||||
CONFIG_MTD_OOPS=y
|
||||
CONFIG_MTD_NAND=y
|
||||
CONFIG_MTD_SPI_NOR=y
|
||||
CONFIG_MTD_UBI=y
|
||||
CONFIG_ZRAM=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/of_irq.h>
|
||||
#ifdef CONFIG_MTD_SPI_NOR
|
||||
#include <linux/mtd/spi-nor.h>
|
||||
#endif
|
||||
#include "spicc.h"
|
||||
|
||||
/* #define CONFIG_SPICC_LOG */
|
||||
@@ -104,6 +107,13 @@ struct spicc {
|
||||
int log_size;
|
||||
int log_count;
|
||||
#endif
|
||||
#ifdef CONFIG_MTD_SPI_NOR
|
||||
struct device *dev;
|
||||
struct spi_nor *nor;
|
||||
int nor_cs;
|
||||
/* used by nor core */
|
||||
struct mutex nor_lock;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SPICC_LOG
|
||||
@@ -339,7 +349,7 @@ static void spicc_set_clk(struct spicc *spicc, int speed)
|
||||
sys_clk_rate = clk_get_rate(spicc->clk);
|
||||
|
||||
if (spicc_get_flag(spicc, FLAG_ENHANCE)) {
|
||||
div = sys_clk_rate/speed;
|
||||
div = DIV_ROUND_UP(sys_clk_rate, speed);
|
||||
if (div < 2)
|
||||
div = 2;
|
||||
div = (div >> 1) - 1;
|
||||
@@ -733,6 +743,136 @@ int dirspi_register_board_info(struct spi_board_info const *info,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dirspi_register_board_info);
|
||||
|
||||
#ifdef CONFIG_MTD_SPI_NOR
|
||||
static int meson_snor_prep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
{
|
||||
struct spicc *spicc = nor->priv;
|
||||
|
||||
mutex_lock(&spicc->nor_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void meson_snor_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
|
||||
{
|
||||
struct spicc *spicc = nor->priv;
|
||||
|
||||
mutex_unlock(&spicc->nor_lock);
|
||||
}
|
||||
|
||||
static int meson_snor_read_reg(struct spi_nor *nor, u8 opcode,
|
||||
u8 *buf, int len)
|
||||
{
|
||||
struct spicc *spicc = nor->priv;
|
||||
int ret;
|
||||
|
||||
gpio_direction_output(spicc->nor_cs, 0);
|
||||
|
||||
ret = spicc_hw_xfer(spicc, &opcode, 0, 1);
|
||||
if (!ret)
|
||||
ret = spicc_hw_xfer(spicc, 0, buf, len);
|
||||
|
||||
gpio_direction_output(spicc->nor_cs, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t meson_snor_read(struct spi_nor *nor, loff_t from,
|
||||
size_t len, u_char *read_buf)
|
||||
{
|
||||
struct spicc *spicc = nor->priv;
|
||||
u8 tx_buf[4];
|
||||
int ret;
|
||||
|
||||
gpio_direction_output(spicc->nor_cs, 0);
|
||||
|
||||
tx_buf[0] = nor->read_opcode;
|
||||
tx_buf[1] = (from >> 16) & 0xff;
|
||||
tx_buf[2] = (from >> 8) & 0xff;
|
||||
tx_buf[3] = from & 0xff;
|
||||
ret = spicc_hw_xfer(spicc, tx_buf, 0, 4);
|
||||
if (!ret)
|
||||
ret = spicc_hw_xfer(spicc, 0, read_buf, len);
|
||||
|
||||
gpio_direction_output(spicc->nor_cs, 1);
|
||||
|
||||
return ret ? 0 : len;
|
||||
}
|
||||
|
||||
static int meson_snor_write_reg(struct spi_nor *nor, u8 opcode,
|
||||
u8 *buf, int len)
|
||||
{
|
||||
struct spicc *spicc = nor->priv;
|
||||
int ret;
|
||||
|
||||
gpio_direction_output(spicc->nor_cs, 0);
|
||||
|
||||
ret = spicc_hw_xfer(spicc, &opcode, 0, 1);
|
||||
if (!ret)
|
||||
ret = spicc_hw_xfer(spicc, buf, 0, len);
|
||||
|
||||
gpio_direction_output(spicc->nor_cs, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t meson_snor_write(struct spi_nor *nor, loff_t to,
|
||||
size_t len, const u_char *write_buf)
|
||||
{
|
||||
struct spicc *spicc = nor->priv;
|
||||
u8 tx_buf[4];
|
||||
int ret;
|
||||
|
||||
gpio_direction_output(spicc->nor_cs, 0);
|
||||
|
||||
tx_buf[0] = nor->program_opcode;
|
||||
tx_buf[1] = (to >> 16) & 0xff;
|
||||
tx_buf[2] = (to >> 8) & 0xff;
|
||||
tx_buf[3] = to & 0xff;
|
||||
ret = spicc_hw_xfer(spicc, tx_buf, 0, 4);
|
||||
if (!ret)
|
||||
ret = spicc_hw_xfer(spicc, (u8 *)write_buf, 0, len);
|
||||
|
||||
gpio_direction_output(spicc->nor_cs, 1);
|
||||
|
||||
return ret ? 0 : len;
|
||||
}
|
||||
|
||||
static struct spi_nor *meson_snor_init(struct spicc *spicc,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct device *dev = spicc->dev;
|
||||
struct spi_nor *nor;
|
||||
struct mtd_info *mtd;
|
||||
|
||||
nor = devm_kzalloc(dev, sizeof(*nor), GFP_KERNEL);
|
||||
if (!nor)
|
||||
return 0;
|
||||
|
||||
nor->dev = dev;
|
||||
spi_nor_set_flash_node(nor, np);
|
||||
nor->priv = spicc;
|
||||
nor->prepare = meson_snor_prep;
|
||||
nor->unprepare = meson_snor_unprep;
|
||||
nor->read_reg = meson_snor_read_reg;
|
||||
nor->write_reg = meson_snor_write_reg;
|
||||
nor->read = meson_snor_read;
|
||||
nor->write = meson_snor_write;
|
||||
nor->erase = NULL;
|
||||
mtd = &nor->mtd;
|
||||
mtd->name = (np->name) ? np->name : "meson_snor";
|
||||
|
||||
if (!spi_nor_scan(nor, NULL, SPI_NOR_NORMAL)) {
|
||||
if (!mtd_device_register(mtd, NULL, 0))
|
||||
return nor;
|
||||
}
|
||||
|
||||
devm_kfree(dev, nor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* end CONFIG_MTD_SPI_NOR */
|
||||
|
||||
/* setting clock and pinmux here */
|
||||
static int spicc_setup(struct spi_device *spi)
|
||||
{
|
||||
@@ -1107,8 +1247,77 @@ static int spicc_probe(struct platform_device *pdev)
|
||||
struct spi_master *master;
|
||||
struct spicc *spicc;
|
||||
int i, ret;
|
||||
#ifdef CONFIG_MTD_SPI_NOR
|
||||
struct device_node *child, *np = pdev->dev.of_node;
|
||||
int speed;
|
||||
#endif
|
||||
|
||||
WARN_ON(!pdev->dev.of_node);
|
||||
spicc = devm_kzalloc(&pdev->dev, sizeof(*spicc), GFP_KERNEL);
|
||||
if (!spicc)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, spicc);
|
||||
ret = of_spicc_get_data(spicc, pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "of error=%d\n", ret);
|
||||
goto err1;
|
||||
}
|
||||
spicc_hw_init(spicc);
|
||||
spicc_log_init(spicc);
|
||||
spicc_log(spicc, 0, 0, PROBE_BEGIN);
|
||||
|
||||
spin_lock_init(&spicc->lock);
|
||||
init_completion(&spicc->completion);
|
||||
if (spicc->irq) {
|
||||
if (request_irq(spicc->irq, spicc_xfer_complete_isr,
|
||||
IRQF_SHARED, "spicc", spicc)) {
|
||||
dev_err(&pdev->dev, "request irq(%d) failed!\n",
|
||||
spicc->irq);
|
||||
spicc->irq = 0;
|
||||
} else
|
||||
disable_irq_nosync(spicc->irq);
|
||||
}
|
||||
spicc_log(spicc, &spicc->irq, 1, REQUEST_IRQ);
|
||||
|
||||
#ifdef CONFIG_MTD_SPI_NOR
|
||||
spicc->dev = &pdev->dev;
|
||||
child = of_get_next_available_child(np, NULL);
|
||||
if (child && of_device_is_compatible(child, "jedec,spi-nor")) {
|
||||
if (of_gpio_named_count(np, "cs-gpios") != 1) {
|
||||
dev_err(&pdev->dev, "nor: cs-gpios error\n");
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
spicc->nor_cs = of_get_named_gpio(np, "cs-gpios", 0);
|
||||
if (!gpio_is_valid(spicc->nor_cs)) {
|
||||
dev_err(&pdev->dev, "nor: invalid cs-gpio\n");
|
||||
ret = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
ret = gpio_request(spicc->nor_cs, dev_name(&pdev->dev));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "nor: request cs-gpio failed\n");
|
||||
goto err1;
|
||||
}
|
||||
gpio_direction_output(spicc->nor_cs, 1);
|
||||
|
||||
ret = of_property_read_u32(child, "frequency", &speed);
|
||||
if (!ret)
|
||||
spicc_set_clk(spicc, speed);
|
||||
|
||||
mutex_init(&spicc->nor_lock);
|
||||
spicc->nor = meson_snor_init(spicc, child);
|
||||
}
|
||||
|
||||
if (spicc->nor)
|
||||
return 0;
|
||||
|
||||
mutex_destroy(&spicc->nor_lock);
|
||||
dev_warn(&pdev->dev, "no snor on spicc bus\n");
|
||||
#endif
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*spicc));
|
||||
if (IS_ERR_OR_NULL(master)) {
|
||||
dev_err(&pdev->dev, "allocate spi master failed!\n");
|
||||
@@ -1116,16 +1325,6 @@ static int spicc_probe(struct platform_device *pdev)
|
||||
}
|
||||
spicc = spi_master_get_devdata(master);
|
||||
spicc->master = master;
|
||||
dev_set_drvdata(&pdev->dev, spicc);
|
||||
ret = of_spicc_get_data(spicc, pdev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "of error=%d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
spicc_hw_init(spicc);
|
||||
spicc_log_init(spicc);
|
||||
spicc_log(spicc, 0, 0, PROBE_BEGIN);
|
||||
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
master->bus_num = spicc->device_id;
|
||||
master->setup = spicc_setup;
|
||||
@@ -1152,21 +1351,8 @@ static int spicc_probe(struct platform_device *pdev)
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
spin_lock_init(&spicc->lock);
|
||||
INIT_LIST_HEAD(&spicc->msg_queue);
|
||||
|
||||
init_completion(&spicc->completion);
|
||||
if (spicc->irq) {
|
||||
if (request_irq(spicc->irq, spicc_xfer_complete_isr,
|
||||
IRQF_SHARED, "spicc", spicc)) {
|
||||
dev_err(&pdev->dev, "master %d request irq(%d) failed!\n",
|
||||
master->bus_num, spicc->irq);
|
||||
spicc->irq = 0;
|
||||
} else
|
||||
disable_irq_nosync(spicc->irq);
|
||||
}
|
||||
spicc_log(spicc, &spicc->irq, 1, REQUEST_IRQ);
|
||||
|
||||
/*setup class*/
|
||||
spicc->cls.name = kzalloc(10, GFP_KERNEL);
|
||||
sprintf((char *)spicc->cls.name, "spicc%d", master->bus_num);
|
||||
@@ -1185,6 +1371,9 @@ static int spicc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
err:
|
||||
spi_master_put(master);
|
||||
|
||||
err1:
|
||||
devm_kfree(&pdev->dev, spicc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1196,6 +1385,9 @@ static int spicc_remove(struct platform_device *pdev)
|
||||
spicc_log_exit(spicc);
|
||||
spi_unregister_master(spicc->master);
|
||||
destroy_workqueue(spicc->wq);
|
||||
#ifdef CONFIG_MTD_SPI_NOR
|
||||
mutex_destroy(&spicc->nor_lock);
|
||||
#endif
|
||||
if (spicc->pinctrl)
|
||||
devm_pinctrl_put(spicc->pinctrl);
|
||||
return 0;
|
||||
@@ -1254,7 +1446,7 @@ static void __exit spicc_exit(void)
|
||||
platform_driver_unregister(&spicc_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(spicc_init);
|
||||
module_init(spicc_init);
|
||||
module_exit(spicc_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic SPICC driver");
|
||||
|
||||
@@ -830,6 +830,11 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{ "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) },
|
||||
|
||||
/* GigaDevice */
|
||||
{
|
||||
"gd25q80c", INFO(0xc84014, 0, 64 * 1024, 16,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||
},
|
||||
{
|
||||
"gd25q32", INFO(0xc84016, 0, 64 * 1024, 64,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
@@ -1009,6 +1014,8 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
|
||||
{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
|
||||
{ "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
|
||||
|
||||
{"FM25Q08A", INFO(0xa14014, 0x0, 64 * 1024, 16, SECT_4K) },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user