aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAnilKumar Ch <anilkumar@ti.com>2012-08-20 07:20:54 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2012-09-21 17:58:47 -0400
commit4cdd34b26826e89972c03043987b83f76e7ad510 (patch)
tree634e385dc93e91b97b12f8e71aec1baaa6db4fdb /drivers
parent2469627d175c1d6d7812a1395dd3ef053a0e65b3 (diff)
can: c_can: Add runtime PM support to Bosch C_CAN/D_CAN controller
Add Runtime PM support to C_CAN/D_CAN controller. The runtime PM APIs control clocks for C_CAN/D_CAN IP and prevent access to the register of C_CAN/D_CAN IP when clock is turned off. Signed-off-by: AnilKumar Ch <anilkumar@ti.com> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/can/c_can/c_can.c49
-rw-r--r--drivers/net/can/c_can/c_can.h1
-rw-r--r--drivers/net/can/c_can/c_can_platform.c1
3 files changed, 49 insertions, 2 deletions
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index 4c538e388655..768bb481b077 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -34,6 +34,7 @@
34#include <linux/if_ether.h> 34#include <linux/if_ether.h>
35#include <linux/list.h> 35#include <linux/list.h>
36#include <linux/io.h> 36#include <linux/io.h>
37#include <linux/pm_runtime.h>
37 38
38#include <linux/can.h> 39#include <linux/can.h>
39#include <linux/can/dev.h> 40#include <linux/can/dev.h>
@@ -201,6 +202,30 @@ static const struct can_bittiming_const c_can_bittiming_const = {
201 .brp_inc = 1, 202 .brp_inc = 1,
202}; 203};
203 204
205static inline void c_can_pm_runtime_enable(const struct c_can_priv *priv)
206{
207 if (priv->device)
208 pm_runtime_enable(priv->device);
209}
210
211static inline void c_can_pm_runtime_disable(const struct c_can_priv *priv)
212{
213 if (priv->device)
214 pm_runtime_disable(priv->device);
215}
216
217static inline void c_can_pm_runtime_get_sync(const struct c_can_priv *priv)
218{
219 if (priv->device)
220 pm_runtime_get_sync(priv->device);
221}
222
223static inline void c_can_pm_runtime_put_sync(const struct c_can_priv *priv)
224{
225 if (priv->device)
226 pm_runtime_put_sync(priv->device);
227}
228
204static inline int get_tx_next_msg_obj(const struct c_can_priv *priv) 229static inline int get_tx_next_msg_obj(const struct c_can_priv *priv)
205{ 230{
206 return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) + 231 return (priv->tx_next & C_CAN_NEXT_MSG_OBJ_MASK) +
@@ -673,11 +698,15 @@ static int c_can_get_berr_counter(const struct net_device *dev,
673 unsigned int reg_err_counter; 698 unsigned int reg_err_counter;
674 struct c_can_priv *priv = netdev_priv(dev); 699 struct c_can_priv *priv = netdev_priv(dev);
675 700
701 c_can_pm_runtime_get_sync(priv);
702
676 reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG); 703 reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
677 bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >> 704 bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
678 ERR_CNT_REC_SHIFT; 705 ERR_CNT_REC_SHIFT;
679 bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK; 706 bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;
680 707
708 c_can_pm_runtime_put_sync(priv);
709
681 return 0; 710 return 0;
682} 711}
683 712
@@ -1053,11 +1082,13 @@ static int c_can_open(struct net_device *dev)
1053 int err; 1082 int err;
1054 struct c_can_priv *priv = netdev_priv(dev); 1083 struct c_can_priv *priv = netdev_priv(dev);
1055 1084
1085 c_can_pm_runtime_get_sync(priv);
1086
1056 /* open the can device */ 1087 /* open the can device */
1057 err = open_candev(dev); 1088 err = open_candev(dev);
1058 if (err) { 1089 if (err) {
1059 netdev_err(dev, "failed to open can device\n"); 1090 netdev_err(dev, "failed to open can device\n");
1060 return err; 1091 goto exit_open_fail;
1061 } 1092 }
1062 1093
1063 /* register interrupt handler */ 1094 /* register interrupt handler */
@@ -1079,6 +1110,8 @@ static int c_can_open(struct net_device *dev)
1079 1110
1080exit_irq_fail: 1111exit_irq_fail:
1081 close_candev(dev); 1112 close_candev(dev);
1113exit_open_fail:
1114 c_can_pm_runtime_put_sync(priv);
1082 return err; 1115 return err;
1083} 1116}
1084 1117
@@ -1091,6 +1124,7 @@ static int c_can_close(struct net_device *dev)
1091 c_can_stop(dev); 1124 c_can_stop(dev);
1092 free_irq(dev->irq, dev); 1125 free_irq(dev->irq, dev);
1093 close_candev(dev); 1126 close_candev(dev);
1127 c_can_pm_runtime_put_sync(priv);
1094 1128
1095 return 0; 1129 return 0;
1096} 1130}
@@ -1133,10 +1167,19 @@ static const struct net_device_ops c_can_netdev_ops = {
1133 1167
1134int register_c_can_dev(struct net_device *dev) 1168int register_c_can_dev(struct net_device *dev)
1135{ 1169{
1170 struct c_can_priv *priv = netdev_priv(dev);
1171 int err;
1172
1173 c_can_pm_runtime_enable(priv);
1174
1136 dev->flags |= IFF_ECHO; /* we support local echo */ 1175 dev->flags |= IFF_ECHO; /* we support local echo */
1137 dev->netdev_ops = &c_can_netdev_ops; 1176 dev->netdev_ops = &c_can_netdev_ops;
1138 1177
1139 return register_candev(dev); 1178 err = register_candev(dev);
1179 if (err)
1180 c_can_pm_runtime_disable(priv);
1181
1182 return err;
1140} 1183}
1141EXPORT_SYMBOL_GPL(register_c_can_dev); 1184EXPORT_SYMBOL_GPL(register_c_can_dev);
1142 1185
@@ -1148,6 +1191,8 @@ void unregister_c_can_dev(struct net_device *dev)
1148 c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS); 1191 c_can_enable_all_interrupts(priv, DISABLE_ALL_INTERRUPTS);
1149 1192
1150 unregister_candev(dev); 1193 unregister_candev(dev);
1194
1195 c_can_pm_runtime_disable(priv);
1151} 1196}
1152EXPORT_SYMBOL_GPL(unregister_c_can_dev); 1197EXPORT_SYMBOL_GPL(unregister_c_can_dev);
1153 1198
diff --git a/drivers/net/can/c_can/c_can.h b/drivers/net/can/c_can/c_can.h
index 4e56baa9c2da..1437a6dbdca5 100644
--- a/drivers/net/can/c_can/c_can.h
+++ b/drivers/net/can/c_can/c_can.h
@@ -153,6 +153,7 @@ struct c_can_priv {
153 struct can_priv can; /* must be the first member */ 153 struct can_priv can; /* must be the first member */
154 struct napi_struct napi; 154 struct napi_struct napi;
155 struct net_device *dev; 155 struct net_device *dev;
156 struct device *device;
156 int tx_object; 157 int tx_object;
157 int current_status; 158 int current_status;
158 int last_status; 159 int last_status;
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index d0a66cf298ba..7b8b7a485d72 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -179,6 +179,7 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev)
179 179
180 dev->irq = irq; 180 dev->irq = irq;
181 priv->base = addr; 181 priv->base = addr;
182 priv->device = &pdev->dev;
182 priv->can.clock.freq = clk_get_rate(clk); 183 priv->can.clock.freq = clk_get_rate(clk);
183 priv->priv = clk; 184 priv->priv = clk;
184 185