diff options
author | Alexander Stein <alexander.stein@systec-electronic.com> | 2014-04-07 02:52:03 -0400 |
---|---|---|
committer | Marc Kleine-Budde <mkl@pengutronix.de> | 2014-04-24 18:08:43 -0400 |
commit | abcd7f750a7e978a60c745e7c41dc468949365c2 (patch) | |
tree | 2cd1b51eec4c9ad827c0ec578457b7623bcba194 | |
parent | 8e964fe21d8186d410353c295df14623a5ed8745 (diff) |
can: c_can: Add support for eg20t (pch_can)
Signed-off-by: Alexander Stein <alexander.stein@systec-electronic.com>
Acked-by: Wolfgang Grandegger <wg@grandegger.com>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
-rw-r--r-- | drivers/net/can/c_can/c_can_pci.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/drivers/net/can/c_can/c_can_pci.c b/drivers/net/can/c_can/c_can_pci.c index bce0be54c2f5..7ab384f59e7e 100644 --- a/drivers/net/can/c_can/c_can_pci.c +++ b/drivers/net/can/c_can/c_can_pci.c | |||
@@ -19,9 +19,13 @@ | |||
19 | 19 | ||
20 | #include "c_can.h" | 20 | #include "c_can.h" |
21 | 21 | ||
22 | #define PCI_DEVICE_ID_PCH_CAN 0x8818 | ||
23 | #define PCH_PCI_SOFT_RESET 0x01fc | ||
24 | |||
22 | enum c_can_pci_reg_align { | 25 | enum c_can_pci_reg_align { |
23 | C_CAN_REG_ALIGN_16, | 26 | C_CAN_REG_ALIGN_16, |
24 | C_CAN_REG_ALIGN_32, | 27 | C_CAN_REG_ALIGN_32, |
28 | C_CAN_REG_32, | ||
25 | }; | 29 | }; |
26 | 30 | ||
27 | struct c_can_pci_data { | 31 | struct c_can_pci_data { |
@@ -31,6 +35,10 @@ struct c_can_pci_data { | |||
31 | enum c_can_pci_reg_align reg_align; | 35 | enum c_can_pci_reg_align reg_align; |
32 | /* Set the frequency */ | 36 | /* Set the frequency */ |
33 | unsigned int freq; | 37 | unsigned int freq; |
38 | /* PCI bar number */ | ||
39 | int bar; | ||
40 | /* Callback for reset */ | ||
41 | void (*init)(const struct c_can_priv *priv, bool enable); | ||
34 | }; | 42 | }; |
35 | 43 | ||
36 | /* | 44 | /* |
@@ -63,6 +71,29 @@ static void c_can_pci_write_reg_aligned_to_32bit(struct c_can_priv *priv, | |||
63 | writew(val, priv->base + 2 * priv->regs[index]); | 71 | writew(val, priv->base + 2 * priv->regs[index]); |
64 | } | 72 | } |
65 | 73 | ||
74 | static u16 c_can_pci_read_reg_32bit(struct c_can_priv *priv, | ||
75 | enum reg index) | ||
76 | { | ||
77 | return (u16)ioread32(priv->base + 2 * priv->regs[index]); | ||
78 | } | ||
79 | |||
80 | static void c_can_pci_write_reg_32bit(struct c_can_priv *priv, | ||
81 | enum reg index, u16 val) | ||
82 | { | ||
83 | iowrite32((u32)val, priv->base + 2 * priv->regs[index]); | ||
84 | } | ||
85 | |||
86 | static void c_can_pci_reset_pch(const struct c_can_priv *priv, bool enable) | ||
87 | { | ||
88 | if (enable) { | ||
89 | u32 __iomem *addr = priv->base + PCH_PCI_SOFT_RESET; | ||
90 | |||
91 | /* write to sw reset register */ | ||
92 | iowrite32(1, addr); | ||
93 | iowrite32(0, addr); | ||
94 | } | ||
95 | } | ||
96 | |||
66 | static int c_can_pci_probe(struct pci_dev *pdev, | 97 | static int c_can_pci_probe(struct pci_dev *pdev, |
67 | const struct pci_device_id *ent) | 98 | const struct pci_device_id *ent) |
68 | { | 99 | { |
@@ -87,7 +118,8 @@ static int c_can_pci_probe(struct pci_dev *pdev, | |||
87 | pci_set_master(pdev); | 118 | pci_set_master(pdev); |
88 | pci_enable_msi(pdev); | 119 | pci_enable_msi(pdev); |
89 | 120 | ||
90 | addr = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); | 121 | addr = pci_iomap(pdev, c_can_pci_data->bar, |
122 | pci_resource_len(pdev, c_can_pci_data->bar)); | ||
91 | if (!addr) { | 123 | if (!addr) { |
92 | dev_err(&pdev->dev, | 124 | dev_err(&pdev->dev, |
93 | "device has no PCI memory resources, " | 125 | "device has no PCI memory resources, " |
@@ -142,11 +174,17 @@ static int c_can_pci_probe(struct pci_dev *pdev, | |||
142 | priv->read_reg = c_can_pci_read_reg_aligned_to_16bit; | 174 | priv->read_reg = c_can_pci_read_reg_aligned_to_16bit; |
143 | priv->write_reg = c_can_pci_write_reg_aligned_to_16bit; | 175 | priv->write_reg = c_can_pci_write_reg_aligned_to_16bit; |
144 | break; | 176 | break; |
177 | case C_CAN_REG_32: | ||
178 | priv->read_reg = c_can_pci_read_reg_32bit; | ||
179 | priv->write_reg = c_can_pci_write_reg_32bit; | ||
180 | break; | ||
145 | default: | 181 | default: |
146 | ret = -EINVAL; | 182 | ret = -EINVAL; |
147 | goto out_free_c_can; | 183 | goto out_free_c_can; |
148 | } | 184 | } |
149 | 185 | ||
186 | priv->raminit = c_can_pci_data->init; | ||
187 | |||
150 | ret = register_c_can_dev(dev); | 188 | ret = register_c_can_dev(dev); |
151 | if (ret) { | 189 | if (ret) { |
152 | dev_err(&pdev->dev, "registering %s failed (err=%d)\n", | 190 | dev_err(&pdev->dev, "registering %s failed (err=%d)\n", |
@@ -193,6 +231,15 @@ static struct c_can_pci_data c_can_sta2x11= { | |||
193 | .type = BOSCH_C_CAN, | 231 | .type = BOSCH_C_CAN, |
194 | .reg_align = C_CAN_REG_ALIGN_32, | 232 | .reg_align = C_CAN_REG_ALIGN_32, |
195 | .freq = 52000000, /* 52 Mhz */ | 233 | .freq = 52000000, /* 52 Mhz */ |
234 | .bar = 0, | ||
235 | }; | ||
236 | |||
237 | static struct c_can_pci_data c_can_pch = { | ||
238 | .type = BOSCH_C_CAN, | ||
239 | .reg_align = C_CAN_REG_32, | ||
240 | .freq = 50000000, /* 50 MHz */ | ||
241 | .init = c_can_pci_reset_pch, | ||
242 | .bar = 1, | ||
196 | }; | 243 | }; |
197 | 244 | ||
198 | #define C_CAN_ID(_vend, _dev, _driverdata) { \ | 245 | #define C_CAN_ID(_vend, _dev, _driverdata) { \ |
@@ -202,6 +249,8 @@ static struct c_can_pci_data c_can_sta2x11= { | |||
202 | static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = { | 249 | static DEFINE_PCI_DEVICE_TABLE(c_can_pci_tbl) = { |
203 | C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN, | 250 | C_CAN_ID(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN, |
204 | c_can_sta2x11), | 251 | c_can_sta2x11), |
252 | C_CAN_ID(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_CAN, | ||
253 | c_can_pch), | ||
205 | {}, | 254 | {}, |
206 | }; | 255 | }; |
207 | static struct pci_driver c_can_pci_driver = { | 256 | static struct pci_driver c_can_pci_driver = { |