1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public |
3 | * License. See the file "COPYING" in the main directory of this archive |
4 | * for more details. |
5 | * |
6 | * Copyright (C) 2011, 2012 Cavium, Inc. |
7 | */ |
8 | |
9 | #include <linux/platform_device.h> |
10 | #include <linux/spi/spi.h> |
11 | #include <linux/module.h> |
12 | #include <linux/io.h> |
13 | #include <linux/of.h> |
14 | |
15 | #include <asm/octeon/octeon.h> |
16 | |
17 | #include "spi-cavium.h" |
18 | |
19 | static int octeon_spi_probe(struct platform_device *pdev) |
20 | { |
21 | void __iomem *reg_base; |
22 | struct spi_controller *host; |
23 | struct octeon_spi *p; |
24 | int err = -ENOENT; |
25 | |
26 | host = spi_alloc_host(dev: &pdev->dev, size: sizeof(struct octeon_spi)); |
27 | if (!host) |
28 | return -ENOMEM; |
29 | p = spi_controller_get_devdata(ctlr: host); |
30 | platform_set_drvdata(pdev, data: host); |
31 | |
32 | reg_base = devm_platform_ioremap_resource(pdev, index: 0); |
33 | if (IS_ERR(ptr: reg_base)) { |
34 | err = PTR_ERR(ptr: reg_base); |
35 | goto fail; |
36 | } |
37 | |
38 | p->register_base = reg_base; |
39 | p->sys_freq = octeon_get_io_clock_rate(); |
40 | |
41 | p->regs.config = 0; |
42 | p->regs.status = 0x08; |
43 | p->regs.tx = 0x10; |
44 | p->regs.data = 0x80; |
45 | |
46 | host->num_chipselect = 4; |
47 | host->mode_bits = SPI_CPHA | |
48 | SPI_CPOL | |
49 | SPI_CS_HIGH | |
50 | SPI_LSB_FIRST | |
51 | SPI_3WIRE; |
52 | |
53 | host->transfer_one_message = octeon_spi_transfer_one_message; |
54 | host->bits_per_word_mask = SPI_BPW_MASK(8); |
55 | host->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; |
56 | |
57 | host->dev.of_node = pdev->dev.of_node; |
58 | err = devm_spi_register_controller(dev: &pdev->dev, ctlr: host); |
59 | if (err) { |
60 | dev_err(&pdev->dev, "register host failed: %d\n" , err); |
61 | goto fail; |
62 | } |
63 | |
64 | dev_info(&pdev->dev, "OCTEON SPI bus driver\n" ); |
65 | |
66 | return 0; |
67 | fail: |
68 | spi_controller_put(ctlr: host); |
69 | return err; |
70 | } |
71 | |
72 | static void octeon_spi_remove(struct platform_device *pdev) |
73 | { |
74 | struct spi_controller *host = platform_get_drvdata(pdev); |
75 | struct octeon_spi *p = spi_controller_get_devdata(ctlr: host); |
76 | |
77 | /* Clear the CSENA* and put everything in a known state. */ |
78 | writeq(val: 0, addr: p->register_base + OCTEON_SPI_CFG(p)); |
79 | } |
80 | |
81 | static const struct of_device_id octeon_spi_match[] = { |
82 | { .compatible = "cavium,octeon-3010-spi" , }, |
83 | {}, |
84 | }; |
85 | MODULE_DEVICE_TABLE(of, octeon_spi_match); |
86 | |
87 | static struct platform_driver octeon_spi_driver = { |
88 | .driver = { |
89 | .name = "spi-octeon" , |
90 | .of_match_table = octeon_spi_match, |
91 | }, |
92 | .probe = octeon_spi_probe, |
93 | .remove_new = octeon_spi_remove, |
94 | }; |
95 | |
96 | module_platform_driver(octeon_spi_driver); |
97 | |
98 | MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver" ); |
99 | MODULE_AUTHOR("David Daney" ); |
100 | MODULE_LICENSE("GPL" ); |
101 | |